Created
May 21, 2024 15:48
-
-
Save ngbrown/01b767f416b4eafc41fce10f6c08a622 to your computer and use it in GitHub Desktop.
SemaphoreSlimExtensions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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