在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
问题抽象:当某个操作的执行必须依赖于另一个操作的完成时,需要有个机制来保证这种先后关系。 1、ManualResetEvent类 using System; using System.Threading; namespace ConsoleApp1 { class Program { //一开始设置为false才会等待收到信号才执行 static ManualResetEvent mr = new ManualResetEvent(false); public static void Main() { Thread t = new Thread(Run); //启动辅助线程 t.Start(); //等待辅助线程执行完毕之后,主线程才继续执行 Console.WriteLine("主线程一边做自己的事,一边等辅助线程执行!" + DateTime.Now.ToString("mm:ss")); mr.WaitOne(); Console.WriteLine("收到信号,主线程继续执行" + DateTime.Now.ToString("mm:ss")); Console.ReadKey(); } static void Run() { //模拟长时间任务 Thread.Sleep(3000); Console.WriteLine("辅助线程长时间任务完成!" + DateTime.Now.ToString("mm:ss")); mr.Set(); } } } 在思维上,这个东西可以有两种用法,一种是让主线程等待辅助线程,一种是辅助线程等待主线程。 Reset方法调用示例 using System; using System.Threading; namespace ConsoleApp1 { class Program { //一开始设置为false,当遇到WaitOne()时,需要Set()才能继续执行 static ManualResetEvent mr = new ManualResetEvent(false); public static void Main() { Thread t = new Thread(Run); Console.WriteLine("开始" + DateTime.Now.ToString("mm:ss")); t.Start(); mr.WaitOne(); Console.WriteLine("第一次等待完成!" + DateTime.Now.ToString("mm:ss")); mr.Reset(); //重置后,又能WaitOne()啦 mr.WaitOne(3000); Console.WriteLine("第二次等待完成!" + DateTime.Now.ToString("mm:ss")); Console.ReadKey(); } static void Run() { mr.Set(); Thread.Sleep(2000); mr.Set(); } } } 如果以上代码不使用Reset,则直接输出第二次等待完成,而不会等待2秒。 2、AutoResetEvent类 using System; using System.Threading; namespace ConsoleApp1 { class Program { static AutoResetEvent ar = new AutoResetEvent(true); public static void Main() { Thread t = new Thread(Run); t.Start(); bool state = ar.WaitOne(1000); Console.WriteLine("当前的信号量状态:{0}", state); state = ar.WaitOne(1000); Console.WriteLine("再次WaitOne后现在的状态是:{0}", state); state = ar.WaitOne(1000); Console.WriteLine("再次WaitOne后现在的状态是:{0}", state); Console.ReadKey(); } static void Run() { Console.WriteLine("当前时间" + DateTime.Now.ToString("mm:ss")); } } }
AutoResetEvent 允许线程通过发信号互相通信。通常,此通信涉及线程需要独占访问的资源。 using System; using System.Threading; namespace ConsoleApp1 { class TestAutoReseEvent { static AutoResetEvent BuyBookEvent = new AutoResetEvent(false); static AutoResetEvent PayMoneyEvent = new AutoResetEvent(false); static AutoResetEvent GetBookEvent = new AutoResetEvent(false); static int number = 10; public static void Run() { Thread buyBookThread = new Thread(new ThreadStart(BuyBookProc)); buyBookThread.Name = "买书线程"; Thread payMoneyThread = new Thread(new ThreadStart(PayMoneyProc)); payMoneyThread.Name = "付钱线程"; Thread getBookThread = new Thread(new ThreadStart(GetBookProc)); getBookThread.Name = "取书线程"; buyBookThread.Start(); payMoneyThread.Start(); getBookThread.Start(); buyBookThread.Join(); payMoneyThread.Join(); getBookThread.Join(); } static void BuyBookProc() { while (number > 0) { Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number); PayMoneyEvent.Set(); BuyBookEvent.WaitOne(); Console.WriteLine("------------------------------------------"); number--; } } static void PayMoneyProc() { while (number > 0) { PayMoneyEvent.WaitOne(); Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number); GetBookEvent.Set(); } } static void GetBookProc() { while (number > 0) { GetBookEvent.WaitOne(); Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number); BuyBookEvent.Set(); } } } } namespace ConsoleApp1 { class Program { public static void Main() { TestAutoReseEvent.Run(); } } } 3、ManualResetEventSlim类 using System; using System.Threading; namespace ConsoleApp1 { class Program { static void Main(string[] args) { var t1 = new Thread(() => TravelThroughGates("Thread 1", 5)); var t2 = new Thread(() => TravelThroughGates("Thread 2", 6)); var t3 = new Thread(() => TravelThroughGates("Thread 3", 12)); t1.Start(); t2.Start(); t3.Start(); Thread.Sleep(TimeSpan.FromSeconds(6)); Console.WriteLine("The gates are now open!"); _mainEvent.Set(); Thread.Sleep(TimeSpan.FromSeconds(2)); _mainEvent.Reset(); Console.WriteLine("The gates have been closed!"); Thread.Sleep(TimeSpan.FromSeconds(10)); Console.WriteLine("The gates are now open for the second time!"); _mainEvent.Set(); Thread.Sleep(TimeSpan.FromSeconds(2)); Console.WriteLine("The gates have been closed!"); _mainEvent.Reset(); } static void TravelThroughGates(string threadName, int seconds) { Console.WriteLine("{0} falls to sleep {1}", threadName, seconds); Thread.Sleep(TimeSpan.FromSeconds(seconds)); Console.WriteLine("{0} waits for the gates to open!", threadName); _mainEvent.Wait(); Console.WriteLine("{0} enters the gates!", threadName); } /// <summary> /// ManualResetEventSlim是ManualResetEvent的混合版本,一直保持大门敞开直到手工调用Reset方法, /// _mainEvent.Set 相当于打开了大门从而允许准备好的线程接收信号并继续工作 /// _mainEvent.Reset 相当于关闭了大门 此时已经准备好执行的信号量 则只能等到下次大门开启时才能够执行 /// </summary> static ManualResetEventSlim _mainEvent = new ManualResetEventSlim(false); } }
|
请发表评论