Waiting for a ManualResetEventSlim to be set asynchronously
ManualResetEventSlim
represents a thread synchronization event that, when signaled, must be reset manually. This is a common synchronization primitive. However, it doesn't expose a method to wait asynchronously. Hopefully, it's not too complicated to create an extension method using ThreadPool.RegisterWaitForSingleObject
and TaskCompletionSource
.
C#
static class Extensions
{
public static Task WaitAsync(this ManualResetEventSlim manualResetEvent, CancellationToken cancellationToken = default)
=> WaitAsync(manualResetEvent.WaitHandle, cancellationToken);
public static Task WaitAsync(this WaitHandle waitHandle, CancellationToken cancellationToken = default)
{
CancellationTokenRegistration cancellationRegistration = default;
var tcs = new TaskCompletionSource();
var handle = ThreadPool.RegisterWaitForSingleObject(
waitObject: waitHandle,
callBack: (o, timeout) =>
{
cancellationRegistration.Unregister();
tcs.TrySetResult();
},
state: null,
timeout: Timeout.InfiniteTimeSpan,
executeOnlyOnce: true);
if (cancellationToken.CanBeCanceled)
{
cancellationRegistration = cancellationToken.Register(() =>
{
handle.Unregister(waitHandle);
tcs.TrySetCanceled(cancellationToken);
});
}
return tcs.Task;
}
}
You can test the previous extension methods using the following code:
C#
var manualResetEvent = new ManualResetEventSlim();
_ = Task.Run(async () =>
{
await Task.Delay(2_000);
Console.WriteLine("Unlock");
manualResetEvent.Set();
});
await manualResetEvent.WaitAsync(cts.Token);
Console.WriteLine("Done");
#Additional resources
- ManualResetEventSlim documentation
- Consider providing async methods to, or an async alternative to, ManualResetEvent/ManualResetEventSlim
- Building Async Coordination Primitives, Part 1: AsyncManualResetEvent
Do you have a question or a suggestion about this post? Contact me!
Enjoy this blog?💖 Sponsor on GitHub