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);
}
}
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.
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.
精彩评论