某玩具需要 零件A、B組裝,零件由個別的產線製作,假設製作速度 A>B;那 A完成後就要在組裝台等 B 送來才能拼組。 在這個情境中 產線 A、B 即是 thread,生產零件是 thread 進行的任務;A 完成後等待 B 的這個行為就是多緒同步。
傳統的方法
用 EventWaitHandle(也就是 AutoResetEvent 或 ManualResetEvent) 控制子緒
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(); }每個需要停等的任務要有一個 handle,它的建構引數 initState = false 表示 unsignaled,在 unsignaled 的狀態下 handle.WaitOne() 會 block 當前的 thread,直到 handle.Set() 送出釋放訊號為止。
在 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"); }是不是好懂一百倍? 語意簡單到不用解釋。
沒有留言:
張貼留言