Events, Delegate and Multithreading

A reader recently asked me about a this common patter, where handler is event

if (Handler != null)  {


He is right, that this is not threadsafe… to see why I clipped a recent update from the Design Guidelines document…


Thoughts, comments always welcome.




      Do use a protected virtual method to raise each event. This is only applicable to unsealed classes, not to structs or sealed classes.

For each event, include a corresponding protected virtual method that raises the event. The purpose of the method is to provide a way for a derived class to handle the event using an override. Overriding is a more flexible, faster, and a more natural way to handle base class events in derived classes. The name of the method is should start with ‘On’ and be followed with the name of the event.

public class AlarmClock {


    public event EventHandler<AlarmRaisedEventArgs> AlarmRaised;


    protected virtual void OnAlarmRaised(AlarmRaisedEventArgs e){

        EventHandler<AlarmRaisedEventArgs> handler = AlarmRaised;

        if (handler != null) {

            handler(this, e);




The derived class can choose not to call the base implementation of the method in its override. Be prepared for this by not including any processing in the method that is required for the base class to work correctly.

Annotation (Eric Gunnerson):

If you have an event in a class, you need to add a null test before you call the delegate. Typically, you would write:


     if (Click != null) Click(this, arg);


There is actually a possible race condition here - the event can be cleared between the first and second line. You would actually want to write:


     ClickHandler handler = Click;

     if (handler != null) handler(this, arg);


You might want to do some other sort of synchronization in other scenarios.


So back to the main question. Why is the null test required? We can't change the existing behavior of calling through a delegate as some apps may depend on it, so it would have to be an addition to the language. We have talked about adding an Invoke() keyword to the language to make this easier, but after a fair bit of discussion, we decided that we couldn't do the right thing all the time, so we elected not to do anything.


Comments (14)
  1. Keith Patrick says:

    This actually reminds me why I never use the "using" keyword. It seems like a nice, clean way to declare a temp variable and reduce its scope, but I have not once tried using that keyword and have it actually compile, because when I say "Oh, this would be a perfect place to use it," it turns out the type I want to instantiate doesn’t support IDisposable.

    Sorry about the tangential rant, but I strongly dislike declaring temp variables to accomodate behavior of the underlying platform rather than satisfy a requirement of my own code

  2. Ken says:

    This doesn’t eliminate the race condition, it merely moves it. While you have guaranteed that you won’t get a null dereference exception on the call, you still stand the chance that the handler will be called after it is disconnected from the event. Like so:

    alarm.AlarmRaised += handler.HandleAlarm;

    // …

    // time passes

    // …

    // alarm.OnAlarmRaised() is called

    // OnAlarmRaised caches AlarmRaised, pointing to handler.HandleAlarm

    // switch to our thread

    alarm.AlarmRaised -= handler.HandleAlarm;


    // switch back to event thread

    // handler.HandleAlarm is called, but handler is no longer valid

  3. John Wood says:

    On the subject of why you should have to test for null on delegates… to retain compatibility, how about offering the option of initializing the event rather than deferring the instantiation of the delegate on the first subscribe? I can understand the syntax might be a little confusing, but you could at least offer the option of an attribute on the event that would instantiate it by default with no subscribers?

  4. Roland Weigelt says:
  5. Anonymous says: &raquo; Interesting Note on Delegates, Events and Multithreading

  6. Anonymous says: &raquo; Interesting Note on Delegates, Events and Multithreading

  7. Roland Weigelt says:
  8. Asher says:

    There are a lot of problems with the current event model, Roy Osherov has an article based on Juval Lowy’s EventHelper class

  9. Jay says:

    My favorite approach is to initalize the event:

    public event EventHandler<AlarmRaisedEventArgs> AlarmRaised = delegate {};

    Now I don’t even need a null check. I can just fire the event.

  10. Dmitriy Zaslavkiy says:

    The approach to make a copy of a delegate is still not thread safe. At least not in principle.

Comments are closed.

Skip to main content