Как да изчакам за ресурс при ползване на await/async?

+4 гласа
125 прегледа
попитан 2016 юли 11 от Nikoleta.V. (4,090 точки)

Не разбирам достатъчно как работят асинхронните концепции в .Net 

Работя със сокети и те изискват буфери за операции с писане и четене и искам да имам обект BufferAllocator, който търси и връща буфери за използване от сокетите. Проблемът е, че когато няма достатъчно памет(или pool-а с буферите е празен) приложенията тярбва да изчакват да се освободи буфер и да има достатъчно памет. 

Как да го направя? 

Ето опростен подобен код да добиете представа: 

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 = 60 байта 

            await _allocator.GetBufferAsync(40); //  60 - 40 = 20 байта 

            await _allocator.GetBufferAsync(40); //  20 < 40 изчаква 

            Console.WriteLine("Worked!");  // <-------+ 

        }); //                                        | 

        Console.ReadKey(); //                         | 

        _allocator.ReleaseBuffer(40); // освобождава 40 байта 

        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(); 

    } 

Ще има няколко сокета, които четат и пишат паралелно. Моля за помощ! 

1 отговор

0 гласа
отговорени 2016 юли 13 от valeri.hristov (7,340 точки)
Когато сама имплементираш async конструкция трябва да използваш TaskCompletionSource. Разглеждай го като сигнализиращ обект. Има пропърти Task, което можеш да връщаш на клиентите и да го изчакват асинхронно.  Ъпдейтваш статуса на task-а чрез методите на TaskCompletionSource(например SetResult). По този начин едната страна известява другата, че трябва да продължи.

Разбира се може да ползваш готови конструкции като SemaphoreSlim или AsyncAutoResetEvent.

Винаги се уверявай, че завършваш task-овете(с резултат, изключение или прекъсване). Иначе ще трябва да се срещнеш с доста неприятни бъгове и deadlock-ове.
...