C#: Thread Safe Event calls

Hello World,

While working on a multi-threaded Windows service that used events heavily, I did some research on how to trigger events in a thread safe manner. Inevitably, one looks for reference material or books that have the respect of the community and Jeffery Richter’s CLR via C# is one such resource.

The Context

In the chapter on Events (Chapter 11, pg 265 in the eBook), Jeffery summarizes the first 3 steps of how to raise events in a thread safe manner by providing a snippet for an extension method that can do this as such:


/// <summary>
/// Raises the specified event.
/// </summary>
/// <typeparam name="TEventArgs">The type of the event args.</typeparam>
/// <param name="e">The e.</param>
/// <param name="sender">The sender.</param>
/// <param name="eventDelegate">The event delegate.</param>
public static void Raise<TEventArgs>(
           this TEventArgs e, 
           object sender, 
           ref EventHandler<TEventArgs> eventDelegate) where TEventArgs : EventArgs
{
      EventHandler<TEventArgs> temp = Interlocked.CompareExchange(ref eventDelegate, null, null);
      if (null != temp)
      {
          temp(sender, e);
      }
}

The above code is supposed to be an improvement over the following way where one uses a temp variable to store the passed in delegate instance and then compares the temp to null:

protected void OnSomeEvent(SomeEventArgs e)           
{
      EventHandler<SomeEventArgs> temp = TheEventHandler;
      if (null != temp)
      {
          temp(this, e);
      }
}

The reason why he proposes the code in the extension method over the simpler approach above is that though in theory delegates are immutable, the code in the second snippet may be optimized away by the compiler to remove the temp variable all together and hence there may be a potential NullRefernceException lurking around in multi-threaded scenarios where whilst one thread checked for null and proceeded to raise the event, another thread removed the delegate from the chain making TheEventHandler null.

The Controversy

I then landed upon this SO question where the exact same scenario is discussed and the accepted answer by Bradley says that we do not need to worry about the compiler optimization talked about above in CLR 2.0 and above as ” the CLR 2.0 Memory Model does not allow reads from the heap to be introduced (rule #2)”. Simply put, when the code with temp is seen by the JIT compiler of v 2.0 and above, it will not read the location pointed to by temp twice, effectively removing the case when a race condition may remove the delegate from the chain.

So, who is right?

Actually, as Bradley says further in the answer, if one is working with the Microsoft CLR, the standard pattern of copying the event handler to temp and comparing with null is absolutely fine. However, for non-Microsoft CLR implementations which do not necessarily have the same memory model, it is still wise to use the pattern suggested by Jeffery.

Now that .NET is open sourced [12 November 2014], my take would be to follow Jeffery’s suggested pattern as there is a strong chance your code may be running on a non-MS CLR.

until next time,

Happy Coding

EDIT [11/11/2015]: More Useful material on Events and race conditions

Eric Lippert’s blog post on Events and Races – Provides more context on why thread safety matters with events

Advertisements
Tagged with: ,
Posted in .NET, Best-Practices, C#
3 comments on “C#: Thread Safe Event calls
  1. Josef says:

    Can I simply say what a comfort to discover somebody who truly understands what they’re talking about over the internet.

    You certainly know how to bring a problem to light and make it important.
    More people must read this and understand this side of the story.
    It’s surprising you are not more popular because
    you definitely have the gift.

    Josef Edward site Edward

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

  • Comic for February 23, 2017
    Dilbert readers - Please visit Dilbert.com to read this feature. Due to changes with our feeds, we are now making this RSS feed a link to Dilbert.com.
%d bloggers like this: