接上文 多線程編程學習筆記——線程同步(一)
四、使用AutoResetEvent
1. 使用AutoResetEvent類來實現從一個線程向另一個線程發出通知。
2.代碼如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; //引入線程 using System.Diagnostics; namespace ThreadSynchronousDemo { class Program { static AutoResetEvent autoResetWork = new AutoResetEvent(false); static AutoResetEvent autoResetMain = new AutoResetEvent(false); static void Main(string[] args) { Console.WriteLine("開始,AutoResetEvent 同步"); string threadName = "線程 1"; var t = new Thread((() => working(threadName, 10))); t.Start(); Console.WriteLine("開始,第一次工作"); autoResetWork.WaitOne();//萬事俱備只欠東風,事情卡在這里了, Console.WriteLine("第一次工作完成"); Console.WriteLine("主線程操作,準備發信號"); Thread.Sleep(TimeSpan.FromSeconds(5)); //發信號,說明值已經被寫進去了。這里的意思是說Set是一個發信號的方法。 autoResetMain.Set(); Console.WriteLine("現在運行第二次工作。"); autoResetWork.WaitOne(); Console.WriteLine("第二次工作完成"); Console.Read(); } static void working(string name,int seconds) { Console.WriteLine("{0} 開始運行工作", name); Thread.Sleep(TimeSpan.FromSeconds(seconds)); Console.WriteLine("{0} 正在工作。。。。。。", name); //發信號,說明值已經被寫進去了。這里的意思是說Set是一個發信號的方法。 autoResetWork.Set(); Console.WriteLine("等待主線程完成工作,并發出信號"); autoResetMain.WaitOne(); Console.WriteLine("主線程發來信號,開始第二次工作"); Thread.Sleep(TimeSpan.FromSeconds(seconds)); Console.WriteLine("{0} 第二次工作正在進行中。。。。。", name); autoResetWork.Set(); } } }
3.程序運行結果,如下圖。
以上程序中,我們定義了兩個AutoResetEvent實例。其中一個是從子線程往主線程發信號 ,另一個是主線程往子線程發信號。我們在構造AutoResetEvent時,傳入了false,定義了這兩個實例的初始狀態unsignaled。這個狀態下,任何線程調用這兩個實例的WaitOne方法將會被阻塞,直到我們調用了Set方法。如果我們在構造的時候傳入了true,則這兩個實例的初始狀態是singnaled,則線程調用WaitOne則會被立即處理。
五、使用ManualResetEventSlim類
1. 使用ManualResetEventSlim在線程間傳遞信號。
2.代碼如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; //引入線程 using System.Diagnostics; namespace ThreadSynchronousDemo { class Program { static ManualResetEventSlim manuResetWork = new ManualResetEventSlim(false); static void Main(string[] args) { Console.WriteLine("開始,ManualResetEventSlim 同步"); string threadName = "線程 1"; string threadName2 = "線程 2"; string threadName3 = "線程 3"; var t = new Thread((() => working(threadName, 3))); var t2 = new Thread((() => working(threadName2, 6))); var t3 = new Thread((() => working(threadName3, 12))); t.Start(); t2.Start(); t3.Start(); Thread.Sleep(TimeSpan.FromSeconds(5)); Console.WriteLine("開始,打開 線程工作大門"); manuResetWork.Set(); //發信號 Thread.Sleep(TimeSpan.FromSeconds(3)); manuResetWork.Reset(); Console.WriteLine("線程工作大門,關閉"); Thread.Sleep(TimeSpan.FromSeconds(10)); Console.WriteLine("打開線程工作大門第二次打開了"); manuResetWork.Set(); //發信號 Thread.Sleep(TimeSpan.FromSeconds(3)); manuResetWork.Reset(); Console.WriteLine("線程工作大門,又關閉了"); Console.Read(); } static void working(string name,int seconds) { Console.WriteLine("{0} 休息", name); Thread.Sleep(TimeSpan.FromSeconds(seconds)); Console.WriteLine("{0} 等待打開線程運行的大門", name); manuResetWork.Wait(); Console.WriteLine("線程運行的大門打開了,{0} 進行工作", name); } } }
3.程序運行結果,如下圖。
當主程序啟動時,首先創建ManualResetEvenSlim類的一個實例,然后啟動了三個線程,等待事件信號通知它們繼續工作。
ManualResetEvenSlim的工作方式有點像人群通過大門,而AutoResetEvent事件像一個旋轉門,一次只能通過一人。
ManualResetEvenSlim打開了大門,一直保持打開,直到調用了Reset方法。直到再次調用Set方法打開 大門。
六、使用CountDownEvent類
1. 使用CountDownEvent信號類來等待直到一定數量的操作完成。
2.代碼如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; //引入線程 using System.Diagnostics; namespace ThreadSynchronousDemo { class Program { static CountdownEvent CountDownWork = new CountdownEvent(2); static void Main(string[] args) { Console.WriteLine("開始,CountdownEvent 同步"); var t = new Thread((() => working("第 1 個工作線程任務", 3))); var t2 = new Thread((() => working("第 2 個工作線程任務", 6))); //var t3 = new Thread((() => working("第 3 個工作線程任務", 12))); t.Start(); t2.Start(); //t3.Start(); Thread.Sleep(TimeSpan.FromSeconds(5)); Console.WriteLine("開始,線程工作計數"); CountDownWork.Wait(); Console.WriteLine("計數完成,2個工作 已經完成!"); //如果把上面代碼注釋的第三個線程還原,釋放對象,可以造成第三個線程的拋出錯誤 CountDownWork.Dispose(); Console.Read(); } static void working(string message,int seconds) { Console.WriteLine("工作前休息 {0}",DateTime.Now.Second); Thread.Sleep(TimeSpan.FromSeconds(seconds)); Console.WriteLine(message); CountDownWork.Signal(); Console.WriteLine("發出計數信號, 工作已經完成一項"); } } }
3.程序運行結果如下圖。
程序啟動時,創建了一個CountDownEven實例,在構造中指定了,當兩個操作完成時給出信號。然后我們啟動了兩個線程進行工作,當第二個線程完成操作時,主線程從等待CountDownEvent的狀態中返回并繼續工作。這個類使用場景是,主線程需要等待多個線程完成工作之后,才能繼續的情形。
缺點:必須要等待指定數量的線程全部完成工作,否則就一直會等待,請確保使用CountDownEvent時,所有線程完成工作后,都要調用Signal方法。
說明:
1) 把上面代碼中注釋的第三個線程的代碼,還原則會出現以下錯誤。
2) 如果把 第三個線程啟用,同時把 CountDownWork.Dispose();注釋,則會出現以下錯誤信息。
文章列表