Skip to content

Latest commit

 

History

History
47 lines (33 loc) · 2.11 KB

AsyncLock.md

File metadata and controls

47 lines (33 loc) · 2.11 KB

Overview

This is the async-ready almost-equivalent of the lock keyword or the Mutex type, similar to Stephen Toub's AsyncLock. It's only almost equivalent because the lock keyword permits reentrancy, which is not currently possible to do with an async-ready lock.

An AsyncLock is either taken or not. The lock can be asynchronously acquired by calling LockAsync, and it is released by disposing the result of that task. AsyncLock taken an optional CancellationToken, which can be used to cancel the acquiring of the lock.

The task returned from LockAsync will enter the Completed state when it has acquired the AsyncLock. That same task will enter the Canceled state if the CancellationToken is signaled before the wait is satisfied; in that case, the AsyncLock is not taken by that task.

Example Usage

The vast majority of use cases are to just replace a lock statement. That is, with the original code looking like this:

private readonly object _mutex = new object();
public void DoStuff()
{
  lock (_mutex)
  {
    Thread.Sleep(TimeSpan.FromSeconds(1));
  }
}

If we want to replace the blocking operation Thread.Sleep with an asynchronous equivalent, it's not directly possible because of the lock block. We cannot await inside of a lock.

So, we use the async-compatible AsyncLock instead:

private readonly AsyncLock _mutex = new AsyncLock();
public async Task DoStuffAsync()
{
  using (await _mutex.LockAsync())
  {
    await Task.Delay(TimeSpan.FromSeconds(1));
  }
}

Advanced Usage

AsyncLock also supports synchronous locking with the Lock method.

You can call Lock or LockAsync with an already-cancelled CancellationToken to attempt to acquire the AsyncLock immediately without actually entering the wait queue.

Really Advanced Usage

The AsyncLock constructor can take an async wait queue; pass a custom wait queue to specify your own queueing logic.