How to await a resource using await / async

I don't quite understand how all of the .Net async programming concepts work (await, async, awaiters, sync context, etc.).

I'm working with sockets and they need buffers for read / write operations, and I want to have a BufferAllocator object that looks for and returns the buffers to be used by the sockets. The point is that there is not enough memory (the buffer pool is empty), applications must wait for a buffer and continue when there is available memory.

How can I implement this?

Ok, this is my homework (just a demo for simplicity, this is not my real code):

class Program
{
    private static BufferAllocator _allocator;

    static void Main(string[] args)
    {
        _allocator = new BufferAllocator(100);   // 100 bytes
        Task.Factory.StartNew(async () =>
        {
            await _allocator.GetBufferAsync(40); // 100 - 40 = 60bytes
            await _allocator.GetBufferAsync(40); //  60 - 40 = 20bytes 
            await _allocator.GetBufferAsync(40); //  20 < 40 (wait)
            Console.WriteLine("Worked!");  // <-------+
        }); //                                        |
        Console.ReadKey(); //                         |
        _allocator.ReleaseBuffer(40); // after pessing a key, release 40 bytes
        Console.ReadKey();
    }

}

class BufferAllocator
{
    private int _availableBytes;
    private SemaphoreSlim _signal = new SemaphoreSlim(0, 1);

    public BufferAllocator(int bufferSize)
    {
        _availableBytes = bufferSize;
    }

    public async Task GetBufferAsync(int size)
    {
        while(_availableBytes < size)
            await _signal.WaitAsync();

        _availableBytes -= size;
    }

    public void ReleaseBuffer(int size)
    {
        _availableBytes += size;
        _signal.Release();
    }
}

      

Note. Several sockets will be read and written in parallel. Please give me the key.

+3


source to share


1 answer


When you actually implement a construct async

, you should probably use TaskCompletionSource

. Think of it as a signal object. It has a property Task

that can be returned to your clients asynchronously in await

. And you update the task status using methods TaskCompletionSource

(for example SetResult

). This is how one party (the producer) "notifies" the other (the consumer of that particular task) that it should resume.

You can of course use an inline construct if appropriate, such SemaphoreSlim

as one based on size, or AsyncAutoResetEvent

.



Make sure to never forget to complete your tasks (with result, exception, or cancellation). Otherwise, you will run into the most annoying bugs / dead ends.

+3


source







All Articles