随笔 - 75  文章 - 0  评论 - 2474  阅读 - 141万

(译)构建Async同步基元,Part 3 AsyncCountdownEvent

传送门:异步编程系列目录……

最近在学习.NET4.5关于“并行任务”的使用。“并行任务”有自己的同步机制,没有显示给出类似如旧版本的:事件等待句柄、信号量、lockReaderWriterLock……等同步基元对象,但我们可以沿溪这一编程习惯,那么这系列翻译就是给“并行任务”封装同步基元对象。翻译资源来源《(译)关于AsyncAwaitFAQ

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同步基元.rar

开始:构建Async同步基元,Part 3 AsyncCountdownEvent

         在我之前的两篇文章中,我已经构建了AsyncManualResetEvent AsyncAutoResetEvent同步基元,在这篇文章中我要创建一个简单的AsyncCountdownEvent

         CountdownEvent是这样一个事件,它允许多个等待者在接收到特定数量的信号后才完成等待。“倒计时事件”思想来自于fork/join模式(Fork/Join模式:分而治之,然后合并结果,这么一种编程模式),通常设计为:初始化一定数量的参与者,而当他们都发出事件信号时,这个倒计时从原始值变为0。当倒计时为0CountdownEvent变成有信号状态,并且所有的等待者可以完成。

         这是我们将构建的目标类型:

1
2
3
4
5
6
public class AsyncCountdownEvent
{
    public AsyncCountdownEvent(int initialCount);
    public Task WaitAsync();
    public void Signal();
}

一个倒计时事件实际是由一个手动重置事件和一个内部计数实现,所以我们的AsyncCountdownEvent将还包含两个成员:

1
2
private readonly AsyncManualResetEvent m_amre = new AsyncManualResetEvent();
private int m_count;

         在类型的构造函数中进行m_count变量初始化,以提供特定数量的参与者。

1
2
3
4
5
6
public AsyncCountdownEvent(int initialCount)
{
    if (initialCount <= 0)
        throw new ArgumentOutOfRangeException("initialCount");
    m_count = initialCount;
}

对于WaitAsync()方法我们直接委托给AsyncManualResetEvent的相应方法。

1
public Task WaitAsync() { return m_amre.WaitAsync(); }

       最后,我们的Signal()方法将递减m_count变量直到值为0,然后调用AsyncManualResetEventset()方法。

1
2
3
4
5
6
7
8
9
10
11
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()方法来实现这个常见的模式。

1
2
3
4
5
public Task SignalAndWait()
{
    Signal();
    return WaitAsync();
}

 

这就是本节要讲的AsyncCountdownEvent

完整源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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

作者:Stephen Toub – MSFT

posted on   滴答的雨  阅读(1816)  评论(9编辑  收藏  举报

点击右上角即可分享
微信分享提示