程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C# 線程間互相通信 AutoResetEvent和ManualResetEvent

C# 線程間互相通信 AutoResetEvent和ManualResetEvent

編輯:C#入門知識

C#線程間互相通信主要用到兩個類:AutoResetEvent和ManualResetEvent。   一、AutoResetEvent   AutoResetEvent 允許線程通過發信號互相通信,線程通過調用 AutoResetEvent 上的 WaitOne 來等待信號。 如果 AutoResetEvent 為非終止狀態,則線程會被阻止,並等待當前控制資源的線程通過調用 Set 來通知資源可用。   下面我用吃快餐的例子來說明這個問題,吃快餐的時候都會排隊付款,收銀員發送收款通知,客戶依次付錢,代碼如下:    復制代碼  1  class Program  2  {  3      //若要將初始狀態設置為終止,則為 true;若要將初始狀態設置為非終止,則為 false  4      static AutoResetEvent autoResetEvent = new AutoResetEvent(false);  5    6      static void Main(string[] args)  7      {  8          Thread t1 = new Thread(() =>  9          { 10              Console.WriteLine("客戶1在排隊等待付錢..."); 11   12              //客戶1調用AutoResetEvent上的WaitOne來等待付錢通知 13              autoResetEvent.WaitOne(); 14              Console.WriteLine("通知來了,客戶1付錢");  15          }); 16          t1.IsBackground = true; 17          t1.Start(); 18   19          Pay();//發送通知  20          Console.ReadKey(); 21      } 22       23      static void Pay() 24      { 25          string tip = Console.ReadLine(); 26          if (tip == "next") 27          { 28              autoResetEvent.Set();//收銀員發送付錢通知,通過調用Set來通知客戶付錢 29          } 30      } 31  } 復制代碼   運行在屏幕中打印:   客戶1在排隊等待付錢... 等收銀員說“next”的時候,向客戶1發送付錢通知(autoResetEvent.Set()),屏幕打印:   客戶1在排隊等待付錢... next 通知來了,客戶1付錢! AutoResetEvent類一次只能通知一個等待的線程,且通知一次過後會立即將AutoResetEvent對象的狀態置為false,也就是如果有兩個客戶都在等待收銀員通知,AutoResetEvent對象的set方法只能通知到第一個客戶,代碼和效果如下:    復制代碼  1  class Program  2  {  3      //若要將初始狀態設置為終止,則為 true;若要將初始狀態設置為非終止,則為 false。  4      static AutoResetEvent autoResetEvent = new AutoResetEvent(false);  5    6      static void Main(string[] args)  7      {  8          Thread t1 = new Thread(() =>  9          { 10              Console.WriteLine("客戶1在排隊等待付錢..."); 11   12              //客戶1調用AutoResetEvent上的WaitOne來等待付錢通知 13              autoResetEvent.WaitOne(); 14              Console.WriteLine("通知來了,客戶1付錢"); 15          }); 16          t1.IsBackground = true; 17          t1.Start(); 18   19          Thread t2 = new Thread(() => 20          { 21              Console.WriteLine("客戶2在排隊等待付錢..."); 22   23              //客戶2調用AutoResetEvent上的WaitOne來等待付錢通知 24              autoResetEvent.WaitOne(); 25              Console.WriteLine("通知來了,客戶2付錢!"); 26          }); 27          t2.IsBackground = true; 28          t2.Start(); 29   30          Pay();//發送通知 31   32          Console.ReadKey(); 33      } 34       35      static void Pay() 36      { 37          string tip = Console.ReadLine(); 38          if (tip == "next") 39          { 40              autoResetEvent.Set();//收銀員發送付錢通知,通過調用Set來通知客戶付錢 41          } 42      } 43  } 復制代碼 運行後屏幕打印:   客戶1在排隊等待付錢... 客戶1在排隊等待付錢... next 通知來了,客戶1付錢!  這就說明在通知完客戶1後,autoResetEvent 的狀態又被置為了false,這時如果要通知到客戶2,就需要在通知完客戶1後,再執行一次通知,在線程1中加上一行代碼,如下:    復制代碼  1  Thread t1 = new Thread(() =>  2  {  3      Console.WriteLine("客戶1在排隊等待付錢...");  4    5      //客戶1調用AutoResetEvent上的WaitOne來等待付錢通知  6      autoResetEvent.WaitOne();  7      Console.WriteLine("通知來了,客戶1付錢");  8    9      autoResetEvent.Set();//讓其再通知下個客戶 10  }); 復制代碼 運行後屏幕打印:   客戶1在排隊等待付錢... 客戶1在排隊等待付錢... next 通知來了,客戶1付錢! 通知來了,客戶2付錢!  這也就說明每調用一次Set,只有一個線程會解除等待,換句話說,有多少個線程就要調用多少次Set,線程才會全部繼續。       二、ManualResetEvent   在AutoResetEvent中,如果要通知兩個線程,則Set方法要被執行兩次,也以快餐店的例子做了舉例,但如果有一天客戶1中彩票了,要請部門的10個同事吃飯,也就是說只要Set一次,所有在等待的線程都會解除等待,相當於收銀員只收一次錢,10個人都可以通過收銀去吃飯,這時我們就要用到ManualResetEvent類,它的用法和AutoResetEvent基本一樣,區別就在於它是一量Set方法發出通知後,要再次阻塞的話就需要手動去修改,也就是調用Reset方法,代碼如下:   復制代碼  1  class Program  2  {  3      //若要將初始狀態設置為終止,則為 true;若要將初始狀態設置為非終止,則為 false。  4      static ManualResetEvent manualResetEvent = new ManualResetEvent(false);  5    6      static void Main(string[] args)  7      {  8          Thread t1 = new Thread(() =>  9          { 10              Console.WriteLine("客戶1在排隊等待付錢..."); 11   12              //客戶1調用manualResetEvent上的WaitOne來等待付錢通知 13              manualResetEvent.WaitOne(); 14              Console.WriteLine("已經有人請客,客戶1不用付錢"); 15          }); 16          t1.IsBackground = true; 17          t1.Start(); 18   19          Thread t2 = new Thread(() => 20          { 21              Console.WriteLine("客戶2在排隊等待付錢..."); 22   23              //客戶2調用manualResetEvent上的WaitOne來等待付錢通知 24              manualResetEvent.WaitOne(); 25              Console.WriteLine("已經有人請客,客戶2不用付錢!"); 26          }); 27          t2.IsBackground = true; 28          t2.Start(); 29   30          Pay();//發送通知 31   32          Console.ReadKey(); 33      } 34       35      static void Pay() 36      { 37          string tip = Console.ReadLine(); 38          if (tip == "next") 39          { 40              manualResetEvent.Set();//收銀員發送付錢通知,通過調用Set來通知客戶付錢 41          } 42      } 43  } 復制代碼 運行後屏幕打印:   客戶1在排隊等待付錢... 客戶1在排隊等待付錢... next 已經有人請客,客戶1不用付錢! 已經有人請客,客戶2不用付錢!   如果收銀員在發送通知後5秒就下班了,就不能再收錢了,這時就要把通知重置掉,讓沒接到通知的客戶繼續處於繼續等待,代碼如下: 復制代碼  1  class Program  2  {  3      //若要將初始狀態設置為終止,則為 true;若要將初始狀態設置為非終止,則為 false。  4      static ManualResetEvent manualResetEvent = new ManualResetEvent(false);  5    6      static void Main(string[] args)  7      {  8          Thread t1 = new Thread(() =>  9          { 10              Console.WriteLine("客戶1在排隊等待付錢..."); 11   12              //客戶1調用manualResetEvent上的WaitOne來等待付錢通知 13              manualResetEvent.WaitOne(); 14              Console.WriteLine("已經有人請客,客戶1不用付錢"); 15          }); 16          t1.IsBackground = true; 17          t1.Start(); 18   19          Thread t2 = new Thread(() => 20          { 21              Console.WriteLine("客戶2在排隊等待付錢..."); 22   23              Thread.Sleep(8000);//客戶2發呆了8秒,這時收銀員已經下班,要繼續等待 24              //客戶2調用manualResetEvent上的WaitOne來等待付錢通知 25              manualResetEvent.WaitOne(); 26              Console.WriteLine("已經有人請客,客戶2不用付錢!"); 27          }); 28          t2.IsBackground = true; 29          t2.Start(); 30   31          Pay();//發送通知 32   33          Console.ReadKey(); 34      } 35   36      static void Pay() 37      { 38          string tip = Console.ReadLine(); 39          if (tip == "next") 40          { 41              manualResetEvent.Set();//收銀員發送付錢通知,通過調用Set來通知客戶付錢 42   43              Timer timer = new Timer(StopPay, null, 0, 5000);//5秒鐘後收銀員下班了,線程要重新等待了 44          } 45      } 46   47      static void StopPay(object s) 48      { 49          manualResetEvent.Reset(); 50          Console.WriteLine("收銀員下班, 後面的客戶要繼續等待"); 51      } 52  } 復制代碼 運行後屏幕打印: 客戶1在排隊等待付錢... 客戶1在排隊等待付錢... next 已經有人請客,客戶1不用付錢! 收銀員下班,後面的客戶要繼續等待   總結 AutoResetEvent和ManualResetEvent的主要區別就在於:AutoResetEvent一次只能通知一個等待線程,通知後自動關閉; 而ManualResetEvent一次可通知很多個等待的線程,但要關閉需要調用Reset方法手動關閉。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved