Skip to content

Instantly share code, notes, and snippets.

@NickStrupat
Last active November 24, 2025 05:15
Show Gist options
  • Select an option

  • Save NickStrupat/6e5bfb2e8461a7f4da50ce6351bf0491 to your computer and use it in GitHub Desktop.

Select an option

Save NickStrupat/6e5bfb2e8461a7f4da50ce6351bf0491 to your computer and use it in GitHub Desktop.
AsyncLock
using System;
using System.Threading;
using System.Threading.Tasks;
/// <summary>
/// A simple FIFO async lock. It does not support recursion/reentrancy.
/// </summary>
public sealed class AsyncLock
{
private Task task = Task.CompletedTask;
public async ValueTask LockAsync(Func<Task> whenLocked, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(whenLocked);
var next = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
var prev = Interlocked.Exchange(ref task, next.Task);
try
{
await prev.WaitAsync(cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
_ = prev.ContinueWith(_ => next.SetResult(), TaskContinuationOptions.ExecuteSynchronously);
throw;
}
try
{
await whenLocked().ConfigureAwait(false);
}
finally
{
next.SetResult();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment