Skip to content

Instantly share code, notes, and snippets.

@yamamaya
Created October 8, 2025 11:22
Show Gist options
  • Select an option

  • Save yamamaya/d506eaa47921a470b46b88afa3571c89 to your computer and use it in GitHub Desktop.

Select an option

Save yamamaya/d506eaa47921a470b46b88afa3571c89 to your computer and use it in GitHub Desktop.
A lightweight lock wrapper that allows SemaphoreSlim to be used with the using pattern.
using System.Diagnostics;
namespace OaktreeLab.Utils.Common {
/// <summary>
/// A lightweight lock wrapper that allows <see cref="SemaphoreSlim"/> to be used with the <c>using</c> pattern.
/// </summary>
[DebuggerStepThrough]
public sealed class SemaphoreSlimLock : IDisposable {
private readonly SemaphoreSlim _semaphore;
private bool _disposed;
private SemaphoreSlimLock( SemaphoreSlim semaphore ) {
_semaphore = semaphore;
}
/// <summary>
/// Acquires the lock synchronously.
/// </summary>
public SemaphoreSlimLock( SemaphoreSlim semaphore, CancellationToken cancellationToken = default ) {
ArgumentNullException.ThrowIfNull( semaphore );
semaphore.Wait( cancellationToken );
_semaphore = semaphore;
}
public void Dispose() {
if ( !_disposed ) {
_semaphore?.Release();
_disposed = true;
}
}
/// <summary>
/// Acquires the lock asynchronously.
/// </summary>
/// <returns>Returns an instance of <see cref="SemaphoreSlimLock"/> when the lock is acquired.</returns>
public static async ValueTask<SemaphoreSlimLock> LockAsync( SemaphoreSlim semaphore, CancellationToken cancellationToken = default ) {
ArgumentNullException.ThrowIfNull( semaphore );
await semaphore.WaitAsync( cancellationToken ).ConfigureAwait( false );
return new SemaphoreSlimLock( semaphore );
}
/// <summary>
/// Attempts to acquire the lock within the specified timeout.
/// </summary>
/// <returns>Returns an instance of <see cref="SemaphoreSlimLock"/> when the lock is acquired.</returns>
/// <exception cref="TimeoutException">Thrown when the operation times out.</exception>
public static async ValueTask<SemaphoreSlimLock> TryLockAsync( SemaphoreSlim semaphore, TimeSpan timeout, CancellationToken cancellationToken = default ) {
ArgumentNullException.ThrowIfNull( semaphore );
if ( await semaphore.WaitAsync( timeout, cancellationToken ).ConfigureAwait( false ) ) {
return new SemaphoreSlimLock( semaphore );
}
throw new TimeoutException( "Failed to acquire the lock within the specified timeout." );
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment