Named Semaphore with async calls
You could use ThreadPool.RegisterWaitForSingleObject to register 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&lt;bool&gt;();

    var reg = ThreadPool.RegisterWaitForSingleObject(handle,
        (state, timedOut) =&gt;
        {
            // Handle timeout
            if (timedOut)
                taskCompletionSource.TrySetCanceled();

            taskCompletionSource.TrySetResult(true);
        }, null, timeout, true);

    // Handle cancellation
    cancellationToken.Register(() =&gt;
    {
        reg.Unregister(handle);
        taskCompletionSource.TrySetCanceled();
    });

    return taskCompletionSource.Task;
}


You could use AwaitWaitHandle in your SemaphoreAsync implementation to await the Semaphore.