一个可以等待的异步计数器

时间:2013-01-14 06:35:28

标签: c# asynchronous task-parallel-library async-await

我有一个连接类,它有几个异步方法,如SendText,SendImage等。

连接类有一个Disconnect方法,当它被调用时,我必须注意在所有异步方法完成执行之前不要开始更改类的内部状态。

我认为实现这一目标的一个好方法是简单地保持执行中的操作数量的总计,然后当我想断开连接时,我可以简单地设置Disconnecting = true然后等待计数达到0 < / p>

我正在考虑与此相关的事情

class ReferenceCounter
{
    void Increment();

    void Decrement();

    async Task WaitForCounterToReachZero();
}

然后当异步操作开始时我可以做

refCounter.Increment();

结束时

refCounter.Decrement();

并在Disconnect方法内部

disconnecting = true;
taskCancellationSource.Cancel();
await refCounter.WaitForCounterToReachZero();
Cleanup();

是否有像这样的内置.NET类?

或者对我来说更重要的是,有更好的方法吗?

如果是同步代码,那就像

一样简单
lock (thisLock)
{
    while (counter > 0)
        Monitor.Wait(thisLock);
}

我刚刚发现内置的CountdownEvent类执行相同的操作,但它没有异步Wait方法,也没有任何事件,所以我必须阻止。

1 个答案:

答案 0 :(得分:4)

好吧,假设你在之后永远不会再增加你把它设为0,你可以这样做:

public class Latch
{
    private int count = 0;
    private readonly TaskCompletionSource<object> tcs =
        new TaskCompletionSource<object>();

    public void Increment()
    {
        Interlocked.Increment(ref count);
    }

    public void Decrement()
    {
        if (Interlocked.Decrement(ref count) == 0)
        {
            tcs.TrySetValue(null);
        }
    }

    public Task Task { get { return tcs.Task; } }
}

然后你可以等待someLatch.Task。或者,您可以使闩锁本身等待:

public TaskAwaiter GetAwaiter()
{
    return tcs.Task.GetAwaiter();
}

你应该考虑一下如何防范“降到0后的数量上升”这个方面 - 想想你想要它做什么。 (在上面的代码中,一旦设置了TCS的值,进一步的等待将立即完成。)