Skip to content

Instantly share code, notes, and snippets.

@ngbrown
Created May 21, 2024 15:48
Show Gist options
  • Save ngbrown/01b767f416b4eafc41fce10f6c08a622 to your computer and use it in GitHub Desktop.
Save ngbrown/01b767f416b4eafc41fce10f6c08a622 to your computer and use it in GitHub Desktop.
SemaphoreSlimExtensions
public static class SemaphoreSlimExtensions
{
/// <summary>
/// Blocks the current thread until it can enter the <see cref="SemaphoreSlim"/>. Returns an <see cref="IDisposable"/> to be used in <c>using</c>.
/// </summary>
/// <param name="semaphore">A <see cref="SemaphoreSlim"/> to lock.</param>
/// <returns>An <see cref="IDisposable"/> that will release the <see cref="SemaphoreSlim"/> when disposed.</returns>
public static IDisposable Lock(this SemaphoreSlim semaphore)
{
semaphore.Wait();
return new SemaphoreReleaser(semaphore);
}
/// <summary>
/// Asynchronously waits to enter the <see cref="SemaphoreSlim"/>, while observing a
/// <see cref="CancellationToken"/>. Returned task resolves an <see cref="IDisposable"/> to be used in <c>using</c>.
/// </summary>
/// <returns>
/// A task that will complete when the semaphore has been entered.
/// Task contains An <see cref="IDisposable"/> that will release the <see cref="SemaphoreSlim"/> when disposed.
/// </returns>
/// <param name="semaphore">A <see cref="SemaphoreSlim"/> to lock.</param>
/// <param name="cancellationToken">
/// The <see cref="CancellationToken"/> token to observe.
/// </param>
public static async Task<IDisposable> LockAsync(this SemaphoreSlim semaphore, CancellationToken cancellationToken = default)
{
var task = semaphore.WaitAsync(cancellationToken);
await task.ConfigureAwait(false);
return task.Status == TaskStatus.RanToCompletion ? new SemaphoreReleaser(semaphore) : new DisposableNoOp();
}
private sealed class SemaphoreReleaser(SemaphoreSlim semaphore) : IDisposable
{
private bool released;
public void Dispose()
{
if (released) return;
semaphore.Release();
this.released = true;
}
}
private sealed class DisposableNoOp : IDisposable
{
public void Dispose()
{
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment