You could use ThreadPool.RegisterWaitForSingleObject to get a callback when a the WaitHandle (Semaphore extends WaitHandle) is signaled.
Together with a TaskCompletionSource you could completely remove all your wait loops.
Example:
private async Task Run()
{
var semaphore = new Semaphore(0, 1);
await AwaitWaitHandle(semaphore, CancellationToken.None, TimeSpan.FromMilliseconds(-1));
}
private Task AwaitWaitHandle(WaitHandle handle, CancellationToken cancellationToken, TimeSpan timeout)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
var reg = ThreadPool.RegisterWaitForSingleObject(handle,
(state, timedOut) =>
{
// Handle timeout
if (timedOut)
taskCompletionSource.TrySetCanceled();
taskCompletionSource.TrySetResult(true);
}, null, timeout, true);
// Handle cancellation
cancellationToken.Register(() =>
{
reg.Unregister(handle);
taskCompletionSource.TrySetCanceled();
});
return taskCompletionSource.Task;
}
You could use AwaitWaitHandle in your SemaphoreAsync implementation to await the Semaphore.