在多线程程序中经常会碰到线程同步:
场景1
主线程启动多个子线程后,主线程需要等待所有的子线程执行完毕后,主线程才能进一步向下执行。
C# 提供了 ManualResetEvent 类为我们的线程同步提供了方便.
ManualResetEvent.WaitAll(new WaitHandle[] { });
WaitAll静态方法提供了阻塞当前线程的执行,直到WaitHandle[]中的每个线程发送了阻塞解除的信号,当前线程才会继续执行。
可以通过将布尔值传递给构造函数来控制 ManualResetEvent 的初始状态,如果初始状态处于终止状态,为 true;否则为 false。
ManualResetEvent.Set() 方法发送阻塞终止的信号,当其它线程收到线程阻塞解除的信号,就会继续执行。
场景:主线程需要对子线程1产生的数据与子线程2产生的数据求和,主线程启动线程1等待生成数据1,启动线程2等待生成数据2,只有当
数据1与数据2生成后,主线程才能对数据求和。
代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Diagnostics; namespace ThreadStudy.Hbb0b0 { /// <summary> /// 本事例说明主线程如何等待辅助线程都执行完毕之后继续执行。 /// 主线程启动辅助线程1生成加数1,启动辅助线程2生成加数2 /// 主线程等待辅助线程1与辅助线程2的生成的加数之后,对加数 /// 进行累加,并输出结果。 /// </summary> class Program { delegate int operateNumber(int a, int b); delegate int generateNumber(int a); static int result1; static int result2; static void Main(string[] args) { //辅助线程1阻塞标志 ManualResetEvent m1 = new ManualResetEvent(false); //辅助线程2的阻塞标志 ManualResetEvent m2 = new ManualResetEvent(false); generateNumber g1 = ThreadTool.GenerateNumber; generateNumber g2 = ThreadTool.GenerateNumber; AsyncCallback g1_callback = delegate(IAsyncResult ar) { result1 = g1.EndInvoke(ar); Console.WriteLine("thread id:{0} current number:{1} block stop", Thread.CurrentThread.ManagedThreadId, result1); //辅助线程阻塞完毕 m1.Set(); }; AsyncCallback g2_callback = delegate(IAsyncResult ar) { result2 = g2.EndInvoke(ar); Console.WriteLine("thread id:{0} current number:{1} block stop", Thread.CurrentThread.ManagedThreadId, result2); //辅助线程阻塞完毕 m2.Set(); }; Console.WriteLine("generate numbers:"); //辅助线程1启动 g1.BeginInvoke(10, g1_callback, null); //辅助线程2启动 g2.BeginInvoke(100, g2_callback, null); //主线线程等待所有辅助线程回归 ManualResetEvent.WaitAll(new WaitHandle[] { m1, m2 }); int sum= ThreadTool.sum(result1, result2); Console.WriteLine("{0}+{1}={2}", result1, result2, sum); Console.Read(); } } public class ThreadTool { /// <summary> /// 生成数字 /// </summary> /// <param name="maxNum"></param> /// <returns></returns> static public int GenerateNumber(int maxNum) { Console.WriteLine("thread Id:{0} generate number", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(5000); int result = new Random((int)DateTime.Now.Ticks).Next(maxNum); return result; } /// <summary> /// 累加结果 /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> static public int sum(int a, int b) { Console.WriteLine("thread Id:{0} gernerate number", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(6000); return a + b; } } }
场景2 :
主线程启动子线程1,子线程2, 只要子线程1或子线程2 任一线程执行完毕,主线程就可以继续执行。
代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ThreadWaitOne { class ThreadStartParameterInfo { /// <summary> /// 线程信号 /// </summary> public ManualResetEvent m_mr; /// <summary> /// 线程等待时间 /// </summary> public int m_waitTicks; public ThreadStartParameterInfo(ManualResetEvent mr,int waitTicks) { m_mr = mr; m_waitTicks = waitTicks; } } public class ThreadTool { private object m_SyncObject = new object(); private int currentThreadId = -1; public void Main() { for (int i = 0; i < 5; i++) { ManualResetEvent mr1 = new ManualResetEvent(false); ManualResetEvent mr2 = new ManualResetEvent(false); ManualResetEvent mr3 = new ManualResetEvent(false); ParameterizedThreadStart pts1 = new ParameterizedThreadStart(this.GenerateNumber); ParameterizedThreadStart pts2 = new ParameterizedThreadStart(this.GenerateNumber); ParameterizedThreadStart pts3 = new ParameterizedThreadStart(this.GenerateNumber); Thread ts1 = new Thread(pts1); Thread ts2 = new Thread(pts1); Thread ts3 = new Thread(pts1); ts1.Start (new ThreadStartParameterInfo(mr1, 3010)); ts2.Start(new ThreadStartParameterInfo(mr2, 3020)); ts3.Start(new ThreadStartParameterInfo(mr3, 3030)); //主线程等待任一线程,任一线程发送阻塞完成信号后,主线程就可以继续执行 ManualResetEvent.WaitAny(new WaitHandle[] { mr1, mr2, mr3 }); Console.WriteLine("Main Thread: The fast thread:{0}", currentThreadId); } } public void GenerateNumber(object resetEvent) { ThreadStartParameterInfo threadInfo = resetEvent as ThreadStartParameterInfo; //ManualResetEvent mr = resetEvent as ManualResetEvent; Console.WriteLine("thread Id:{0} wait:{1} generate number start:.....", Thread.CurrentThread.ManagedThreadId,threadInfo.m_waitTicks); Thread.Sleep(threadInfo.m_waitTicks); int radomNumber = new Random((int)DateTime.Now.Ticks).Next(1000); lock(m_SyncObject) { currentThreadId = Thread.CurrentThread.ManagedThreadId; } Console.WriteLine("thread Id:{0} generate number:{1}", Thread.CurrentThread.ManagedThreadId, radomNumber); threadInfo.m_mr.Set(); } } }