某玩具需要 零件A、B組裝,零件由個別的產線製作,假設製作速度 A>B;那 A完成後就要在組裝台等 B 送來才能拼組。 在這個情境中 產線 A、B 即是 thread,生產零件是 thread 進行的任務;A 完成後等待 B 的這個行為就是多緒同步。
傳統的方法
用 EventWaitHandle(也就是 AutoResetEvent 或 ManualResetEvent) 控制子緒
每個需要停等的任務要有一個 handle,它的建構引數 initState = false 表示 unsignaled,在 unsignaled 的狀態下 handle.WaitOne() 會 block 當前的 thread,直到 handle.Set() 送出釋放訊號為止。
- static AutoResetEvent handleA = new AutoResetEvent(false);
- static AutoResetEvent handleB = new AutoResetEvent(false);
- static void Main(string[] args)
- {
- for (int i = 0; i > 2; i++)
- {
- Task.Run(() =>
- {
- Console.WriteLine("Start to create component A");
- Thread.Sleep(2500);
- Console.WriteLine("Finished component A");
- handleA.Set();
- });
- Task.Run(() =>
- {
- Console.WriteLine("Start to create component B");
- Thread.Sleep(5000);
- Console.WriteLine("Finished component B");
- handleB.Set();
- });
- Console.WriteLine("Wait for components");
- handleA.WaitOne();
- handleB.WaitOne();
- // 上面兩行可以取代成 WaitHandle.WaitAll(new WaitHandle[] { handleA, handleB });
- Console.WriteLine("Assemble the toy");
- Console.WriteLine("Toy created");
- }
- Console.ReadLine();
- }
在 Demo 中我們在兩個 thread 開始後就用 handleA, B 都 WaitOne()把主緒 block 住,等待個別任務的最後一行 Set() 對 handle 個別解鎖;兩個 handle 都解鎖之後主緒即恢復運行。
AutoResetEvent vs ManualResetEvent
兩者的差異就就像字面上一樣,ManualResetEvent 在 Set() 之後需要手動 Reset() 調整回 unsignal 的狀態,否則 WaitOne() 將不會發生作用;把前面 Demo 的 AutoResetEvent 都改成 ManualResetEvent 即可觀察到第二 loop 時 WaitOne 未 block 主緒。
ref: MSDN
Quick sum up
1. 一個任務,一個 handle
2. EventWaitHandle 的 ctor 一般是給 false,因為我們希望它一開始就是可以 block 緒的狀態
3. handle.WaitOne() 會 block 當前的 thread;handle.Set() 則會釋放
4. AutoResetEvent 比較常用,因為不用特意去 Reset()
傳統方法不管是寫還是閱讀都不甚直觀,之所以還是提一下是因為常 mantain 到,來看看新方法吧!
TPL Task.WaitAll()
是不是好懂一百倍? 語意簡單到不用解釋。
- for (int i = 0; i < 2; i++)
- {
- Task taskA = Task.Run(() =>
- {
- Console.WriteLine("Start to create component A");
- Thread.Sleep(2500);
- Console.WriteLine("Finished component A");
- });
- Task taskB = Task.Run(() =>
- {
- Console.WriteLine("Start to create component B");
- Thread.Sleep(5000);
- Console.WriteLine("Finished component B");
- });
- Console.WriteLine("Wait for components");
- Task.WaitAll(new Task[] { taskA, taskB });
- Console.WriteLine("Assemble the toy");
- Console.WriteLine("Toy created");
- }
沒有留言:
張貼留言