Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Extension method thread safe?

Is this Extension method thread safe?

   public static class Extensions
   {
      public static void Raise<T>(this EventHandler<T> handler,
        object sender, T args) where T : EventArgs
      {
         if (handler != null) handler(sender, args);
      }
   }

or do I need to change it to this?

   public static class Extensions
   {
      public static void Raise<T>(this EventHandler<T> handler,
        object sender, T args) where T : EventArgs
      {
         var h = handler;
         if (h!= null) h(sender, args);
      }
   }
like image 213
SwDevMan81 Avatar asked Jan 06 '11 19:01

SwDevMan81


2 Answers

You found an interesting loop hole, it tripped everybody up. No, it is not thread-safe.

While it looks like the EventHandler<> reference is copied through the method argument, this is not what happens at runtime. Extension methods are subject to being inlined, just like a regular instance method. In fact, it is extremely likely to get inlined since it is so small. There's no copy, you have to make one yourself.

like image 166
Hans Passant Avatar answered Nov 16 '22 13:11

Hans Passant


Neither version is threadsafe, depending on what you mean by "threadsafe". Consider your second version:

   var h = handler;          
   if (h!= null) 
       h(sender, args);

"handler" is a copy of some field that has an immutable delegate in it. Suppose that field is mutated to "null" on another thread after the null check. Your code does not crash in that case, because you've made a copy of the original not-null value. But merely not crashing does not make the program thread safe. A program that doesn't crash but still produces the wrong results is still not threadsafe.

Suppose when the other thread set the event field to null, it also mutated some state that the previous contents needed to run correctly. You are now going to run an event handler that depends on state that was just mutated on another thread; you're running a stale event handler.

There is no easy way to protect against this problem; if that's the situation you're in, then you're going to have to design your threading logic extremely carefully in order to deal with the situation.

like image 45
Eric Lippert Avatar answered Nov 16 '22 14:11

Eric Lippert