Pregunta

We all know the problems when dealing with .NET events in multi-threading environment. One of them is when we trying to invoke event without copying to the local variable:

if (MyEvent != null)
    MyEvent(this, EventArgs.Empty);

In such cases we can get a race condition if after one thread checks MyEvent != null, another one unsubscribe handler from the event. (then MyEvent trying to fire and ops.. NullRefException)

The solution (proposed by J.Richter) is to copy event handler to the local variable:

var handler = MyEvent;
if (handler != null)
    handler(this, EventArgs.Empty); 

This works well, coz

Delegates are immutable; once created, the invocation list of a delegate does not change.

But as i know AMD64 JIT does some optimizations which can ignore local copy and reads an actual value of the event handler. (an article is old but i can't find any actual inf. about such issue).

So, how actually CLR JIT works in such cases? Can there be a NullReferenceException?

¿Fue útil?

Solución

The blog post is incomplete, it doesn't tell the story what they did about it. It is old, posted a year before the x64 jitter was actually released. They probably discovered the problem while testing.

His assertion that volatile should be used is not entirely inaccurate. That however requires looking at the problem with C compiler glasses. Or the way the x86 jitter implemented volatile. Unfortunately, the C# language suffers from a seriously broken definition of volatile, arbitrarily pulled out to deal with processors with a weak memory model. The Itanium was the principal troublemaker there. Screwed up enough to have Joe Duffy just completely give up and declare it evil.

The solution they came up was rather drastic, they completely eliminated the need for volatile, it has no affect on code generation at all. And the event firing pattern was rescued along for the ride, the x64 jitter does in fact copy and store the reference. Not in a local variable but in a CPU register, x64 has plenty of those. Otherwise a standard optimizer feature.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top