最近在學習.NET4.5關於“並行任務”的使用。“並行任務”有自己的同步機制,沒有顯示給出類似如舊版本的:事件等待句柄、信號量、lock、ReaderWriterLock……等同步基元對象,但我們可以沿溪這一編程習慣,那么這系列翻譯就是給“並行任務”封裝同步基元對象。翻譯資源來源《(譯)關於Async與Await的FAQ》
1. 構建Async同步基元,Part 1 AsyncManualResetEvent
2. 構建Async同步基元,Part 2 AsyncAutoResetEvent
3. 構建Async同步基元,Part 3 AsyncCountdownEvent
4. 構建Async同步基元,Part 4 AsyncBarrier
5. 構建Async同步基元,Part 5 AsyncSemaphore
6. 構建Async同步基元,Part 6 AsyncLock
7. 構建Async同步基元,Part 7 AsyncReaderWriterLock
開始:構建Async同步基元,Part 3 AsyncCountdownEvent
在我之前的兩篇文章中,我已經構建了AsyncManualResetEvent 和AsyncAutoResetEvent同步基元,在這篇文章中我要創建一個簡單的AsyncCountdownEvent。
CountdownEvent是這樣一個事件,它允許多個等待者在接收到特定數量的信號后才完成等待。“倒計時事件”思想來自於fork/join模式(Fork/Join模式:分而治之,然后合並結果,這么一種編程模式),通常設計為:初始化一定數量的參與者,而當他們都發出事件信號時,這個倒計時從原始值變為0。當倒計時為0時CountdownEvent變成有信號狀態,並且所有的等待者可以完成。
這是我們將構建的目標類型:
public class AsyncCountdownEvent { public AsyncCountdownEvent(int initialCount); public Task WaitAsync(); public void Signal(); }
一個倒計時事件實際是由一個手動重置事件和一個內部計數實現,所以我們的AsyncCountdownEvent將還包含兩個成員:
private readonly AsyncManualResetEvent m_amre = new AsyncManualResetEvent(); private int m_count;
在類型的構造函數中進行m_count變量初始化,以提供特定數量的參與者。
public AsyncCountdownEvent(int initialCount) { if (initialCount <= 0) throw new ArgumentOutOfRangeException("initialCount"); m_count = initialCount; }
對於WaitAsync()方法我們直接委托給AsyncManualResetEvent的相應方法。
public Task WaitAsync() { return m_amre.WaitAsync(); }
最后,我們的Signal()方法將遞減m_count變量直到值為0,然后調用AsyncManualResetEvent的set()方法。
public void Signal() { if (m_count <= 0) throw new InvalidOperationException(); int newCount = Interlocked.Decrement(ref m_count); if (newCount == 0) m_amre.Set(); else if (newCount < 0) throw new InvalidOperationException(); }
AsyncCountdownEvent類型還有一個常見的模式:用它作為一種形式的關卡|屏障,一個參與者發出到達信號並且等待其他參與者到達。為了達到此目的,我們能還可以添加一個簡單的SignalAndWait()方法來實現這個常見的模式。
public Task SignalAndWait() { Signal(); return WaitAsync(); }
這就是本節要講的AsyncCountdownEvent。
完整源碼如下:
public class AsyncCountdownEvent { // 手動重置事件 private readonly AsyncManualResetEvent m_amre = new AsyncManualResetEvent(); // 一個內部計數 private int m_count; public AsyncCountdownEvent(int initialCount) { if (initialCount <= 0) throw new ArgumentOutOfRangeException("initialCount"); m_count = initialCount; } public Task WaitAsync() { return m_amre.WaitAsync(); } public void Signal() { if (m_count <= 0) throw new InvalidOperationException(); int newCount = Interlocked.Decrement(ref m_count); if (newCount == 0) m_amre.Set(); else if (newCount < 0) throw new InvalidOperationException(); } // 用它作為一種形式的關卡|屏障,一個參與者發出到達信號並且等待其他參與者到達。 public Task SignalAndWait() { Signal(); return WaitAsync(); } }
下一節,我將實現一個async版本的Barrier。
推薦閱讀:
感謝你的觀看……
原文:《Building Async Coordination Primitives, Part 3: AsyncCountdownEvent》