能够看到 WaitHandle是 事件(EventWaitHandle)、互斥体(Mutex)、信号量(Sempahore)的父类。spa
WaitHandle咱们最常常使用的方法,并是使用它的静态方法WaitAll. 咱们会发如今这个WaitHandle里面只有等待方法,也就是它会阻塞当前线程的执行。线程
那么如何要解除它对当前线程的阻塞呢,那么就须要依赖于各个子类的方法了。3d
例如如今有一个这样的场景,如何在一个方法中,等待全部的线程所有执行完,最后再统计获得的计算结果呢?code
WaitHandle[] handlers = new WaitHandle[]{ new AutoResetEvent(false), new AutoResetEvent(false), new AutoResetEvent(false), new AutoResetEvent(false), new AutoResetEvent(false), new AutoResetEvent(false), new AutoResetEvent(false), new AutoResetEvent(false) }; for (var i = 0; i < handlers.Length; i++) { ThreadPool.QueueUserWorkItem(ar => { int index = (int)ar; Thread.Sleep(1000); AppCenter.AppendLog("任务:" + index + "开始执行!"); (handlers[index] as AutoResetEvent).Set(); }, i); } ThreadPool.QueueUserWorkItem(ar => { WaitHandle.WaitAll(handlers); AppCenter.AppendLog("全部任务都已经完成了,我不用再等待了。"); });
这个方法,能够方便实现两个线程之间的相互通讯。blog
如何实现两个线程的相互通讯?事件
EventWaitHandle handleA = new AutoResetEvent(false); EventWaitHandle handleB = new AutoResetEvent(false); ThreadPool.QueueUserWorkItem(ar => { AppCenter.AppendLog("A:我是A,我已经开始运行了"); Thread.Sleep(2000); AppCenter.AppendLog("A:我想睡觉了,B你先跑跑吧。"); EventWaitHandle.SignalAndWait(handleB, handleA); AppCenter.AppendLog("A:开始工做ing"); Thread.Sleep(3000); AppCenter.AppendLog("A:这个有点难,问下B"); EventWaitHandle.SignalAndWait(handleB, handleA); AppCenter.AppendLog("A:不错,今天任务搞定,我也闪人了。"); }); ThreadPool.QueueUserWorkItem(ar => { handleB.WaitOne(); AppCenter.AppendLog("B:我是B,我已经顶替A开始运行了。"); Thread.Sleep(5000); AppCenter.AppendLog("B:个人事情已经作完了,该让A搞搞了,休息一会。"); EventWaitHandle.SignalAndWait(handleA, handleB); AppCenter.AppendLog("B:hi,A我搞定了,下班了。"); handleA.Set(); });
那么AutoResetEvent和ManualResetEvent有什么区别呢?咱们先作个实验。get
private EventWaitHandle manualEvent = new ManualResetEvent(false); private void ManualResetEvent_Click(object sender, EventArgs e) { AppCenter.CleanLogs(); ThreadPool.QueueUserWorkItem(ar => { int i = 0; while (true) { manualEvent.WaitOne(); //ManualResetEvent的Set()方法,让事件的终止状态永远为true,让这里一直能执行。 i++; //而AutoResetEvent的Set()方法,初始化让这里执行一次,而后再次执行时是非终止的。将阻塞原有线程的执行 AppCenter.AppendLog("#" + i.ToString()); Thread.Sleep(1000); } }); } private void button2_Click(object sender, EventArgs e) { manualEvent.Set(); } private void button3_Click(object sender, EventArgs e) { manualEvent.Reset(); }
运行结果it
咱们会发现ManualResetEvent在触发Set()方法会,解除了原有的线程的 WaitOne方法,会一直打印输出。class
而当咱们替换为AutoResetEvent方法时候。object
此时每次只会打印一个输出。由于它将 事件的状态设置为终止后,又变为了false.
应用场景,若是有多个线程跑,我可否每次控制3个线程一块儿跑呢。
Semaphore sempore = new Semaphore(0, 3); for (int i = 0; i < 8; i++) { ThreadPool.QueueUserWorkItem(ar => { sempore.WaitOne(); AppCenter.AppendLog("\t第:" +((int)ar).ToString() + "个开始运行."); },i); } ThreadPool.QueueUserWorkItem(ar => { for (int i = 0; i < 3; i++) { AppCenter.AppendLog("第" + (i + 1).ToString() + "批开始执行."); sempore.Release(3); Thread.Sleep(5000); } });
运行结果: