.NET 4.0 以降、自動生成された追加/削除イベント ハンドラーはスレッド セーフです ( hereおよびhere )。したがって、リスナーを公開されたイベントに登録するクライアントは、競合することなく複数のスレッドから同時に登録できます。
しかし、スレッド セーフな方法でイベントを発生させたい場合はどうすればよいでしょうか。推奨される方法は次のようです ( here ):
public event EventHandler MyEvent;
protected void OnMyEvent(EventArgs e)
{
EventHandler myEvent = MyEvent;
if (myEvent != null)
{
myEvent(this, e);
}
}
ただし、.NET メモリ モデル (MSDN マガジン 2012-12 および 2013-01 など) について何か読んだことがありますが、これは正しくないと思います。私の懸念は、メモリ読み取りがコンパイラによって導入される可能性があるため、上記のコードを次のように JIT することができるということです。
public event EventHandler MyEvent;
protected void OnMyEvent(EventArgs e)
{
// JIT removed the local variable and introduced two memory reads instead.
if (MyEvent != null)
{
// A race condition may cause the following line to throw a NullReferenceException.
MyEvent(this, e);
}
}
シングルスレッド環境で実行された場合、メソッドの動作は変わらないため、ローカル変数を削除して繰り返しメモリ読み取りを使用することは合法です。これは ECMA 仕様 ( ECMA-335: I.12.6.4 ) によるものです。わかりやすい例は、MSDN マガジンの 2013 年 1 月号にも掲載されています。
ここで何か不足していますか?そうでない場合は、回避策をアドバイスしてください。