Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

An asynchronous counter which can be awaited on

I have a connection class which has several async methods such as SendText, SendImage etc.

The connection class has a Disconnect method, and when it is called I have to be careful not to start changing the inner state of the class before all async methods have completed execution.

I believe a good way to achieve this is to simply keep a running total of the number of operations in execution, and then when I want to Disconnect I can simply set Disconnecting = true and then wait for the count to reach 0

I'm thinking of something along the lines of this

class ReferenceCounter
{
    void Increment();

    void Decrement();

    async Task WaitForCounterToReachZero();
}

Then when an async operation starts I could do

refCounter.Increment();

When it ends

refCounter.Decrement();

and inside the Disconnect method

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

Are there any built in .NET classes like this?

Or more importantly for me, is there a better way of doing this?

If it was synchronous code it would be as simple as

lock (thisLock)
{
    while (counter > 0)
        Monitor.Wait(thisLock);
}

I just found the built in CountdownEvent class which does the same thing, but it has no async Wait method nor does it have any events, so I'd have to block.

like image 722
NoPyGod Avatar asked Jan 14 '13 06:01

NoPyGod


People also ask

What are asynchronous Counters?

Asynchronous counters are those whose output is free from the clock signal. Because the flip flops in asynchronous counters are supplied with different clock signals, there may be delay in producing output. The required number of logic gates to design asynchronous counters is very less. So they are simple in design.

What is asynchronous up down counter?

An asynchronous up-down counter includes a plurality of counter blocks. Each of the counter blocks has a counter output, an up-down control output, and an up-down control input. A counter signal output from each of the counter blocks has at least two bits.

What is asynchronous in c3?

The async keyword turns a method into an async method, which allows you to use the await keyword in its body. When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete. await can only be used inside an async method.


1 Answers

Well, assuming you'll never increment again after you make it 0, you could do something like this:

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; } }
}

Then you can await someLatch.Task. Alternatively, you could make the latch itself awaitable:

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

You should probably consider how you want to guard against the "count rises after getting down to 0" aspect thuogh - think about what you'd want it to do. (In the code above, once the TCS's value has been set, further awaits will complete immediately.)

like image 129
Jon Skeet Avatar answered Oct 05 '22 13:10

Jon Skeet