Dan McKinley
Math, Programming, and Minority Reports

Thread Safety in VB-2003 Events
January 15th, 2005

Brad Abrams had a recent post about how the usual way of raising an event in C#:

protected virtual void OnMyEvent(EventArgs e)
{
    if(MyEvent != null)
    {
        MyEvent(this, e);
    }
}

is not threadsafe. Purely out of curiosity, I wondered if VB handles this the correct way:

protected virtual void OnMyEvent(EventArgs e)
{
    EventHandler handler = MyEvent;
    if(handler != null)
    {
        handler(this, e);
    }
}

Since VB abstracts this away with the RaiseEvent keyword. Unfortunately it doesn’t seem to, as this code:

Protected Overridable Sub OnMyEvent(ByVal e As EventArgs)
    RaiseEvent MyEvent(Me, e)
End Sub

Compiles to this:

.method family newslot virtual instance void OnMyEvent([mscorlib]System.EventArgs e) cil managed
{
      // Code Size: 22 byte(s)
      .maxstack 8
      L_0000: ldarg.0
      L_0001: ldfld [mscorlib]System.EventHandler VbConsoleApp.Test::MyEventEvent
      L_0006: brfalse.s L_0015
      L_0008: ldarg.0
      L_0009: ldfld [mscorlib]System.EventHandler VbConsoleApp.Test::MyEventEvent
      L_000e: ldarg.0
      L_000f: ldarg.1
      L_0010: callvirt instance void [mscorlib]System.EventHandler::Invoke(object, [mscorlib]System.EventArgs)
      L_0015: ret
}

Which has a race condition—it should store the delegate in a local. Generally, the answer to these questions is “it is fixed in 2005” — so I’m going to just assume that that is the case here.

Back home