CountdownEvent for synchronization

· by Raghu Rajagopalan · Read in about 3 min · (451 words) ·

In the .Net framework a CountdownEvent is an object that represents a thread synchronization primitive that is signaled when its count reaches zero. It can be used to wait for N events to happen before letting a thread proceed further. This has a number of applications when you’re trying to co-ordinate multiple threads.

One example is say when you perform an action that generates some events. Let’s say that your application also lets you register handlers for events and these handlers are (possibly) invoked on a different thread. This might look something like this

class DomainEvent
{
    public DateTime Timestamp { get; set; }
}

class SystemUnderTest
{
    private List<Action<DomainEvent>> handlers = new List<Action<DomainEvent>>();
    public DomainEvent EmitEvent()
    {
        var ev = new DomainEvent() {Timestamp = DateTime.Now};
        Task.Run(() => handlers.ForEach(action => action(ev)));
        return ev;
    }

    public void AddHandler(Action<DomainEvent> h)
    {
        handlers.Add(h);
    }
}

Now, if you have to test this class, ideally, you’d like to call SystemUnderTest.EmitEvent and ensure that any registered eventhandlers are indeed invoked. We might try something like this:

[TestFixture]
class ASimpleTest
{
    [Test]
    public void should_wait_for_threads_to_complete()
    {
        DomainEvent receivedEvent = null;
        var s = new SystemUnderTest(); (1)

        s.AddHandler(@event =>          (2)
            {
            receivedEvent = @event;
            });

        var returnedEvent = s.EmitEvent(); (3)

        Assert.That(returnedEvent.Timestamp, Is.EqualTo(receivedEvent.Timestamp)); (4)
    }
}
1 Create the object
2 register a handler
3 Act - call the method.
4 However, since the eventhandler is invoked on a different thread, we’d like to execute this only after we know for sure that the handler has been invoked.

Basically between (3) and (4), we need to block the main thread. We could use Thread.sleep but that isn’t ideal since we never know how much is the right time to wait. This is a simple thread synchronization problem and in this case,something that a CountdownEvent can help us with. Let’s look at the synchronized version:

[TestFixture]
class ASimpleTest
{
    [Test]
    public void should_wait_for_threads_to_complete()
    {
        CountdownEvent latch = new CountdownEvent(1); (1)
        DomainEvent receivedEvent = null;
        var s = new SystemUnderTest();

        s.AddHandler(@event =>
        {
            receivedEvent = @event;
            latch.Signal();                 (2)
        });

        var returnedEvent = s.EmitEvent();

        latch.Wait(500);                (3)
        Assert.That(returnedEvent.Timestamp, Is.EqualTo(receivedEvent.Timestamp));
    }
}
1 Create a CountdownEvent with a initial count as 1
2 Signal the latch - this will decrement the count by 1.
3 Block the main thread till the CountdownEvent gets to 0 (or 500ms max)

Now, admittedly, this example is a little contrived - we could have achieved the same with a mutex or a semaphore - but consider if we had to wait for more than one event to be received? In that case, it makes a lot more sense to just use a higher order synchronization object like a CountdownEvent rather than basic synchronization primitives like mutexes.

Happy hacking!