Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the TPL equivalent of a condition variable?

I'm learning the Task Parallel Library (in conjunction with C# 5.0 async/await), and I want to do something like this:

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

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

In a traditional threaded model, I can accomplish this using condition variables. What is the TPL solution to this problem?

like image 225
Matthew Avatar asked May 20 '13 19:05

Matthew


People also ask

What is a conditional variable?

A conditional variable in operating system programming is a special kind of variable that is used to determine if a certain condition has been met or not. It is used to communicate between threads when certain conditions become true. A conditional variable is like a queue.

What is condition variable in C?

A condition variable is an explicit queue that threads can put themselves on when some state of execution (i.e., some condition) is not as desired (by waiting on the condition); some other thread, when it changes said state, can then wake one (or more) of those waiting threads and thus allow them to continue (by sig- ...

How do you create a condition variable?

Creating and destroying condition variables A condition variable is created by calling the pthread_cond_init subroutine. You may specify a condition attributes object. If you specify a NULL pointer, the condition variable will have the default attributes.

How do conditional variables work?

Condition variables are synchronization primitives that enable threads to wait until a particular condition occurs. Condition variables are user-mode objects that cannot be shared across processes. Condition variables enable threads to atomically release a lock and enter the sleeping state.


1 Answers

If you just have a one-at-a-time notification, you can use 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();
  }
}

Another option is to use a semaphore (SemaphoreSlim), which will "remember" if it's been signalled previously:

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

If you truly need a condition variable, you can use AsyncConditionVariable from my AsyncEx library:

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();
    }
  }
}
like image 164
Stephen Cleary Avatar answered Oct 18 '22 02:10

Stephen Cleary