Skip to main content
2 of 3
edited body

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.