| 
 | 
	
 
 
  [源码下载] 
 
 
 
 
重新想象 Windows 8 Store Apps (47) - 多线程之线程同步: Semaphore, CountdownEvent, Barrier, ManualResetEvent, AutoResetEvent   
作者:webabcd 
 
介绍 
重新想象 Windows 8 Store Apps 之 线程同步 
 
 
- Semaphore - 信号量
 
 - CountdownEvent - 通过信号数量实现线程同步
 
 - Barrier - 屏障
 
 - ManualResetEvent - 手动红绿灯
 
 - AutoResetEvent - 自动红绿灯
 
     
示例 
1、演示 Semaphore 的使用 
Thread/Lock/SemaphoreDemo.xaml 
 
 
 
 
 
 
 
 
 
 
  Thread/Lock/SemaphoreDemo.xaml.cs 
 
 
 
/* 
* 演示 Semaphore 的使用 
*  
* Semaphore - 信号量 
* SemaphoreSlim - 轻量级的 Semaphore 
*  
* 注: 
* 直译 Semaphore 的话不太好理解,可以将 Semaphore 理解为一个许可证中心,该许可证中心的许可证数量是有限的 
* 线程想要执行就要先从许可证中心获取一个许可证(如果许可证中心的许可证已经发完了,那就等着,等着其它线程归还许可证),执行完了再还回去 
*/ 
using System; 
using System.Collections.Generic; 
using System.Threading; 
using System.Threading.Tasks; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Navigation; 
namespace XamlDemo.Thread.Lock 
{ 
public sealed partial class SemaphoreDemo : Page 
{ 
/* 
* Semaphore(int initialCount, int maximumCount, string name) 
*     initialCount - 许可证中心初始拥有的许可证数量,即初始情况下已经发出的许可证数量为 maximumCount - initialCount 
*     maximumCount - 许可证中心总共拥有的许可证数量 
*     name - 许可证中心的名称 
* Semaphore OpenExisting(string name) - 打开指定名称的许可证中心 
*/ 
// 实例化一个许可证中心,该中心拥有的许可证数量为 2 个 
private Semaphore _semaphore = new Semaphore(2, 2); 
public SemaphoreDemo() 
{ 
this.InitializeComponent(); 
} 
protected async override void OnNavigatedTo(NavigationEventArgs e) 
{ 
List tasks = new List(); 
// 模拟 5 个线程并行执行,拿到许可证的线程才能运行,而许可证中心只有 2 个许可证 
for (int i = 0; i < 5; i++) 
{ 
CancellationToken token = new CancellationTokenSource().Token; 
Task task = Task.Run( 
() => 
{ 
OutMsg(string.Format("task {0} 等待一个许可证", Task.CurrentId)); 
token.WaitHandle.WaitOne(5000); 
// WaitOne() - 申请许可证 
                        _semaphore.WaitOne(); 
OutMsg(string.Format("task {0} 申请到一个许可证", Task.CurrentId)); 
token.WaitHandle.WaitOne(1000); 
OutMsg(string.Format("task {0} 归还了一个许可证", Task.CurrentId)); 
// int Release() - 归还许可证,返回值为:Release() 之前许可证中心可用的许可证数量 
int ignored = _semaphore.Release(); 
// int Release(int releaseCount) - 指定释放的信号量的次数(按本文的理解就是指定归还的许可证数量) 
                    }, 
token); 
tasks.Add(task); 
} 
await Task.WhenAll(tasks); 
} 
private void OutMsg(string msg) 
{ 
var ignored = Dispatcher.RunAsync( 
Windows.UI.Core.CoreDispatcherPriority.High,  
() =>  
{ 
lblMsg.Text += msg; 
lblMsg.Text += Environment.NewLine; 
}); 
} 
} 
} 
   
2、演示 CountdownEvent 的使用 
Thread/Lock/CountdownEventDemo.xaml 
 
 
 
 
 
 
 
 
 
 
  Thread/Lock/CountdownEventDemo.xaml.cs 
 
 
 
/* 
* 演示 CountdownEvent 的使用 
*  
* CountdownEvent - 通过信号数量实现线程同步 
*/ 
using System.Threading; 
using System.Threading.Tasks; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Navigation; 
namespace XamlDemo.Thread.Lock 
{ 
public sealed partial class CountdownEventDemo : Page 
{ 
private static int _count; 
public CountdownEventDemo() 
{ 
this.InitializeComponent(); 
} 
protected override void OnNavigatedTo(NavigationEventArgs e) 
{ 
// 初始信号数量为 100 个 
using (CountdownEvent countdown = new CountdownEvent(100)) 
{ 
// AddCount(), AddCount(int signalCount) - 增加 1 个信号,或增加指定数量的信号 
// Reset(), Reset(int count) - 重置为初始的信号数量,或重置为指定的信号数量 
// Signal(), Signal(int signalCount) - 减少 1 个信号,或减少指定数量的信号 
// CurrentCount - 获取当前的信号数量 
for (int i = 0; i < 100; i++) 
{ 
Task task = Task.Run( 
() => 
{ 
Interlocked.Increment(ref _count); 
// 减少 1 个信号 
                            countdown.Signal(); 
}); 
} 
// 阻塞当前线程,直到 CountdownEvent 的信号数量变为 0 
                countdown.Wait(); 
lblMsg.Text = "count: " + _count.ToString(); 
} 
} 
} 
} 
   
3、演示 Barrier 的使用 
Thread/Lock/BarrierDemo.xaml 
 
 
 
 
 
 
 
 
 
 
  Thread/Lock/BarrierDemo.xaml.cs 
 
 
 
/* 
* 演示 Barrier 的使用 
*  
* Barrier - 屏障 
*  
* 按如下方式理解: 
* 1、Participant - 参与者 
* 2、SignalAndWait() - 某一个参与者已经到达屏障了 
* 3、所有参与者都到达屏障后,屏障解除 
*/ 
using System.Threading; 
using System.Threading.Tasks; 
using Windows.UI.Core; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Navigation; 
namespace XamlDemo.Thread.Lock 
{ 
public sealed partial class BarrierDemo : Page 
{ 
private static int _count; 
public BarrierDemo() 
{ 
this.InitializeComponent(); 
} 
protected override void OnNavigatedTo(NavigationEventArgs e) 
{ 
// AddParticipant(), AddParticipants(int participantCount) - 增加 1 个参与者,或增加指定数量的参与者 
// RemoveParticipant(), RemoveParticipants(int participantCount) - 减少 1 个参与者,或减少指定数量的参与者 
// ParticipantCount - 获取参与者总数 
// ParticipantsRemaining - 尚未到达屏障的参与者总数 
 
Barrier barrier = new Barrier( 
5, // 初始有 5 个参与者 
(ctx) => // 屏障解除之后 
                { 
var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.High, 
() => 
{ 
lblMsg.Text = "count: " + _count.ToString(); 
}); 
}); 
for (int i = 0; i < 5; i++) 
{ 
Task task = Task.Run( 
() => 
{ 
Interlocked.Increment(ref _count); 
// 某一个参与者已经到达屏障了 
                        barrier.SignalAndWait(); 
// SignalAndWait(int millisecondsTimeout) - 指定一个超时时间 
// SignalAndWait(CancellationToken cancellationToken) - 指定一个 CancellationToken 
                    }); 
} 
} 
} 
} 
   
4、演示 ManualResetEvent 的使用 
Thread/Lock/ManualResetEventDemo.xaml 
 
 
 
 
 
 
 
 
 
 
  Thread/Lock/ManualResetEventDemo.xaml.cs 
 
 
 
/* 
* 演示 ManualResetEvent 的使用 
*  
* ManualResetEvent - 手动红绿灯 
* ManualResetEventSlim - 轻量级的 ManualResetEvent 
*/ 
using System; 
using System.Threading; 
using System.Threading.Tasks; 
using Windows.Foundation; 
using Windows.System.Threading; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Navigation; 
namespace XamlDemo.Thread.Lock 
{ 
public sealed partial class ManualResetEventDemo : Page 
{ 
// true - 指定初始状态为绿灯 
private ManualResetEvent _manualResetEvent = new ManualResetEvent(true); 
private static int _count = 0; 
public ManualResetEventDemo() 
{ 
this.InitializeComponent(); 
} 
protected override void OnNavigatedTo(NavigationEventArgs e) 
{ 
ManualResetEvent sleep = new ManualResetEvent(false); 
Task tas = Task.Run( 
() => 
{ 
while (true) 
{ 
// WaitOne() - 判断:绿灯则进入,红灯则阻塞 
                        _manualResetEvent.WaitOne(); 
/* 
* WaitOne(1000)  
*     1、如果当前是绿灯则进入 
*     2、如果当前是红灯则阻塞 
*         a) 1000 毫秒之内收到 Set() 信号则进入 
*         b) 1000 毫秒之后如果还没收到 Set() 信号则强行进入 
*/ 
IAsyncAction ignored = Windows.System.Threading.ThreadPool.RunAsync( 
(threadPoolWorkItem) => 
{ 
// 在当前线程 sleep 1000 毫秒(WinRT 中没有 Thread.Sleep() 了) 
sleep.WaitOne(1000); 
OutMsg(string.Format("count:{0}, time:{1}", ++_count, DateTime.Now.ToString("mm:ss"))); 
// Set() - 发出绿灯信号,并设置为绿灯 
                                _manualResetEvent.Set(); 
}, 
WorkItemPriority.High); 
// Reset() - 发出红灯信号,并设置为红灯 
                        _manualResetEvent.Reset();  
} 
}); 
} 
private void OutMsg(string msg) 
{ 
var ignored = Dispatcher.RunAsync( 
Windows.UI.Core.CoreDispatcherPriority.High, 
() => 
{ 
lblMsg.Text = msg; 
}); 
} 
} 
} 
   
5、演示 AutoResetEvent 的使用 
Thread/Lock/AutoResetEventDemo.xaml 
 
 
 
 
 
 
 
 
 
 
  Thread/Lock/AutoResetEventDemo.xaml.cs 
 
 
 
/* 
* 演示 AutoResetEvent 的使用 
*  
* AutoResetEvent - 自动红绿灯 
*  
* AutoResetEvent 和 ManualResetEvent 的区别在于:AutoResetEvent 在 WaitOne() 进入之后会自动 Reset() 
*/ 
using System; 
using System.Threading; 
using System.Threading.Tasks; 
using Windows.Foundation; 
using Windows.System.Threading; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Navigation; 
namespace XamlDemo.Thread.Lock 
{ 
public sealed partial class AutoResetEventDemo : Page 
{ 
// true - 指定初始状态为绿灯 
private AutoResetEvent _autoResetEvent = new AutoResetEvent(true); 
private static int _count = 0; 
public AutoResetEventDemo() 
{ 
this.InitializeComponent(); 
} 
protected override void OnNavigatedTo(NavigationEventArgs e) 
{ 
ManualResetEvent sleep = new ManualResetEvent(false); 
Task tas = Task.Run( 
() => 
{ 
while (true) 
{ 
// WaitOne() - 判断:绿灯则进入,红灯则阻塞,进入之后自动 Reset() 
                        _autoResetEvent.WaitOne(); 
/* 
* WaitOne(1000)  
*     1、如果当前是绿灯则进入,进入之后自动 Reset() 
*     2、如果当前是红灯则阻塞 
*         a) 1000 毫秒之内收到 Set() 信号则进入,进入之后自动 Reset() 
*         b) 1000 毫秒之后如果还没收到 Set() 信号则强行进入,进入之后自动 Reset() 
*/ 
IAsyncAction ignored = Windows.System.Threading.ThreadPool.RunAsync( 
(threadPoolWorkItem) => 
{ 
// 在当前线程 sleep 1000 毫秒(WinRT 中没有 Thread.Sleep() 了) 
sleep.WaitOne(1000); 
OutMsg(string.Format("count:{0}, time:{1}", ++_count, DateTime.Now.ToString("mm:ss"))); 
// Set() - 发出绿灯信号,并设置为绿灯 
                                _autoResetEvent.Set(); 
}, 
WorkItemPriority.High); 
} 
}); 
} 
private void OutMsg(string msg) 
{ 
var ignored = Dispatcher.RunAsync( 
Windows.UI.Core.CoreDispatcherPriority.High, 
() => 
{ 
lblMsg.Text = msg; 
}); 
} 
} 
} 
   
OK 
[源码下载] |   
 
 
 
 | 
  
 |