C# 如何使用wait/async等待资源

C# 如何使用wait/async等待资源,c#,.net,asynchronous,task-parallel-library,async-await,C#,.net,Asynchronous,Task Parallel Library,Async Await,我不完全理解所有.Net异步编程概念(wait、async、waiters、sync context等)是如何工作的 我正在使用套接字,它们需要缓冲区来执行读/写操作,我希望有一个BufferAllocator对象来搜索和返回套接字使用的缓冲区。关键是当没有足够的内存可用时(缓冲池为空),应用程序应该等待缓冲区,并在所需的内存可用时继续 我如何实现这一点 好的,这是我的家庭作业(只是为了简单起见的一个演示,它不是我真正的代码): 类程序 { 专用静态缓冲分配器_分配器; 静态void Main(

我不完全理解所有.Net异步编程概念(wait、async、waiters、sync context等)是如何工作的

我正在使用套接字,它们需要缓冲区来执行读/写操作,我希望有一个BufferAllocator对象来搜索和返回套接字使用的缓冲区。关键是当没有足够的内存可用时(缓冲池为空),应用程序应该等待缓冲区,并在所需的内存可用时继续

我如何实现这一点

好的,这是我的家庭作业(只是为了简单起见的一个演示,它不是我真正的代码):

类程序
{
专用静态缓冲分配器_分配器;
静态void Main(字符串[]参数)
{
_分配器=新的缓冲分配器(100);//100字节
Task.Factory.StartNew(异步()=>
{
wait _allocator.GetBufferAsync(40);//100-40=60字节
wait _allocator.GetBufferAsync(40);//60-40=20字节
wait _allocator.GetBufferAsync(40);//20<40(wait)

Console.WriteLine(“工作!”);//当您实际实现一个
异步
构造自己时,您可能应该使用
TaskCompletionSource
。将其视为一个信号对象。它有一个
Task
属性,您可以将其返回给客户端以异步方式等待
。并且您可以使用
TaskCompletionS>更新任务的状态Source
的方法(例如,
SetResult
)。这是一方(生产者)“通知”另一方(消费者该特定任务)它应该恢复的方式

当然,如果适合的话,您可以使用内置构造,比如基于大小的
信号量lim
,或者
AsyncAutoResetEvent


确保你永远不会忘记完成你的任务(结果是例外或取消)。否则,您将面临最令人不快的错误/死锁。

我创建了一个tcs并返回其Taks属性,以便在调用SetResult时通知使用者,我知道了。我不知道在哪里调用SetResult方法。我的意思是,当调用我的ReleaseBuffer方法时,它应该验证是否有可用内存,对吗?如果是的,如果GetBufferAsync方法可以被调用多次,我在哪里共享请求的大小值?我很难想象他会如何使用这里的
TaskCompletionSource
。等待内部结构是否足以满足他的要求?@lontivero@YuvalItzchakov如果没有缓冲区返回任务,您将返回任务您希望调用方等待。当您有缓冲区返回时,您结束该任务,因此您“唤醒”具有缓冲区的调用方。这可能是当有人返回缓冲区时,或者当您决定创建更多缓冲区时。如果缓冲区的数量始终与您可以使用的
SemaphoreSlim
相同。如果它是动态的,您需要直接使用
TaskCompletionSource
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();
    }
}