【问题标题】:What is the TPL equivalent of a condition variable?条件变量的 TPL 等价物是什么?
【发布时间】:2013-05-21 03:28:41
【问题描述】:

我正在学习任务并行库(结合 C# 5.0 async/await),我想做这样的事情:

public class Foo
{
    public void UnblockDoSomething()
    {
        DoWork();
        // notify DoSomethingAsync
    }

    public async Task DoSomethingAsync()
    {
        DoSomeWork();
        await ... // Wait until UnblockDoSomething is called
        DoMoreWork();
    }
}

在传统的线程模型中,我可以使用条件变量来完成此操作。这个问题的 TPL 解决方案是什么?

【问题讨论】:

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


    【解决方案1】:

    如果您只有一次通知,可以使用TaskCompletionSource

    public class Foo
    {
      private TaskCompletionSource<object> _signal = new TaskCompletionSource<object>();
    
      public void UnblockDoSomething()
      {
        DoWork();
        _signal.SetResult(null);
        _signal = new TaskCompletionSource<object>();
      }
    
      public async Task DoSomethingAsync()
      {
        var continueSignal = _signal.Task;
        DoSomeWork();
        await continueSignal;
        DoMoreWork();
      }
    }
    

    另一种选择是使用信号量 (SemaphoreSlim),如果之前已发出信号,它将“记住”:

    public class Foo
    {
      private readonly SemaphoreSlim _mutex = new SemaphoreSlim(0);
    
      public void UnblockDoSomething()
      {
        DoWork();
        _mutex.Release();
      }
    
      public async Task DoSomethingAsync()
      {
        DoSomeWork();
        await _mutex.WaitAsync();
        DoMoreWork();
      }
    }
    

    如果你真的需要条件变量,可以使用我的AsyncEx library中的AsyncConditionVariable

    public class Foo
    {
      private readonly AsyncLock _mutex = new AsyncLock();
      private readonly AsyncConditionVariable _cv = new AsyncConditionVariable(_mutex);
    
      public void UnblockDoSomething()
      {
        using (await _mutex.LockAsync())
        {
          DoWork();
          _cv.Notify();
        }
      }
    
      public async Task DoSomethingAsync()
      {
        using (await _mutex.LockAsync())
        {
          DoSomeWork();
          await _cv.WaitAsync();
          DoMoreWork();
        }
      }
    }
    

    【讨论】:

    • 为了稍微扩展第一个选项,DoSomethingAsync 可以接受 Task 类型的参数,表示依赖关系。它可以等待。然后调用者可以创建一个 TCS,将相应的 Task 传递给 DoSomethingAsync 并将 TCS 传递给 UnblockDoSomething 以允许它设置结果。
    猜你喜欢
    • 2012-03-14
    • 1970-01-01
    • 2023-03-25
    • 2016-08-26
    • 2014-05-08
    • 2014-06-12
    • 1970-01-01
    • 2022-11-28
    相关资源
    最近更新 更多