Skip to content

Instantly share code, notes, and snippets.

@jnm2
Created July 19, 2025 19:49
Show Gist options
  • Save jnm2/9539f1ba8f43c28d37e655acaa19dc87 to your computer and use it in GitHub Desktop.
Save jnm2/9539f1ba8f43c28d37e655acaa19dc87 to your computer and use it in GitHub Desktop.
public sealed class AsyncAutoResetEvent
{
private readonly Lock @lock = new();
private Task? currentWait;
private TaskCompletionSource? taskCompletionSource;
public void Set()
{
lock (@lock)
{
if (currentWait is null)
{
currentWait = Task.CompletedTask;
}
else if (!currentWait.IsCompleted)
{
currentWait = null;
taskCompletionSource!.TrySetResult();
}
}
}
public Task WaitAsync()
{
lock (@lock)
{
if (currentWait is null)
{
taskCompletionSource = new();
currentWait = taskCompletionSource.Task;
}
else if (currentWait.IsCompleted)
{
var originalTask = currentWait;
currentWait = null;
return originalTask;
}
return currentWait;
}
}
}
using Shouldly;
public class AsyncAutoResetEventTests
{
[Test]
public void The_event_is_initially_not_signaled()
{
var ev = new AsyncAutoResetEvent();
ev.WaitAsync().IsCompleted.ShouldBeFalse();
}
[Test]
public void The_event_can_be_signaled_before_waiting_starts()
{
var ev = new AsyncAutoResetEvent();
ev.Set();
ev.WaitAsync().IsCompleted.ShouldBeTrue();
}
[Test]
public void The_event_can_be_signaled_after_waiting_starts()
{
var ev = new AsyncAutoResetEvent();
var waitTask = ev.WaitAsync();
ev.Set();
waitTask.IsCompleted.ShouldBeTrue();
}
[Test]
public void The_event_automatically_resets_when_signaled_after_the_first_wait_starts()
{
var ev = new AsyncAutoResetEvent();
ev.WaitAsync();
ev.Set();
ev.WaitAsync().IsCompleted.ShouldBeFalse();
}
[Test]
public void The_event_automatically_resets_when_signaled_before_the_first_wait_starts()
{
var ev = new AsyncAutoResetEvent();
ev.Set();
ev.WaitAsync();
ev.WaitAsync().IsCompleted.ShouldBeFalse();
}
[Test]
public void Setting_multiple_times_does_not_signal_more_than_one_wait()
{
var ev = new AsyncAutoResetEvent();
ev.Set();
ev.Set();
ev.WaitAsync();
ev.WaitAsync().IsCompleted.ShouldBeFalse();
}
[Test]
public void Multiple_waits_for_the_same_signal_are_the_same_task()
{
var ev = new AsyncAutoResetEvent();
ev.WaitAsync().ShouldBeSameAs(ev.WaitAsync());
ev.Set();
ev.WaitAsync().ShouldBeSameAs(ev.WaitAsync());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment