Saturday, January 25, 2014

Safest way to use EventHandlers in multi-threaded environment

Nowadays MVVM is one of the most common architectural structure and hope most of us working on WPF, Silverlight, Windows Phone or Windows Store apps might have come across this. When talking about MVVM, the first thing which strikes in mind is INotifyPropertyChanged interface. The usual and most common practice of implementing INotifyPropertyChanged is:

public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void RaisePropertyChanged(string prop)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
            }
        }
    }

What do you think about the above code? In first sight, it looks correct, but is it really perfect or thread safe? Well, here answer is NO. One very minor thing is missing in above code which can lead your application to crash in multi-threaded environment.

If you will inspect the above snippet closely, you will notice that the way event is handled here is the culprit. In multi-threaded scenarios, above code can create lot of chaos. Well, enough of suspense. To figure out this hidden culprit, let's take an easy and small snippet.

if (PropertyChanged != null)
     {
         PropertyChanged(this, null);
     }

Now, dig the code line-by-line. In above 2 line snippet:
  • First line executes on thread #1: if(PropertyChanged ! = null) 
  • At this point, PropertyChanged has an event attached to it. So, first line will return true.
  • Meanwhile, on thread #2, the object that has it's event handler attached to PropertyChanged removes it from PropertyChanged.
  • But thread #1 already did it's null check, so it moves on to next statement.
  • On thread #1, next line executes: PropertyChanged(this, null);
  • But the PropertyChanged event no longer has any associated event handlers attached to it, so it throws a NullReferenceException
Hope by this time, you understood the issue with above sort of code. Now question is, how to resolve this issue???

No worries. It's very simple and can be resolved by introducing a temporary variable as shown below:

EventHandler temporaryVariable = PropertyChanged;
if (temporaryVariable != null)
     {
           temporaryVariable(this, null);
     }

After doing the above changes, once the null check is happened, instead of calling PropertyChanged(this, null), thread #1 will call temporaryVariable(this, null); The temporaryVariable is keeping track of all the event handlers that were attached to PropertyChanged, so that statement won't throw a NullReferenceException.

In computer science terms, above problem is called Race condition. Hope you enjoyed this small and useful tip.

No comments:

Post a Comment