2011-01-06 48 views
6

この拡張メソッドはスレッドセーフですか?拡張メソッドはスレッドセーフですか?

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); 
     } 
    } 

またはこれを変更する必要がありますか?

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); 
     } 
    } 
+0

スレッディングに関するイベントの設計と実装の詳細http://stackoverflow.com/questions/786383/c-events-and-thread-safety – user44298

答えて

9

あなたは興味深いループホールを見つけました。いいえ、スレッドセーフではありません。

のように見えますが、<のように、のように見えますが、参照はメソッド引数でコピーされますが、これは実行時には起こりません。拡張メソッドは、通常のインスタンスメソッドと同様に、インライン化されることがあります。実際にはと非常に小さいので、非常にになる可能性があります。コピーはありません。自分で作成する必要があります。

+1

私はあなたが正しいとは思っていません。これは、呼び出し元の関数が別のスレッド(ローカル変数の代わりにクラスフィールド)によって変更される可能性のある値に対してメソッドを呼び出すときにのみ適用されます。その場合、JITがそのような呼び出しをインラインにするかどうかわかりません。 – tster

+0

しかし、これは非常に興味深いトピックです。私は仕事に就いていなかったので、これ以上掘り下げる時間があったといい。 – tster

+1

これは、イベントを発生させるコードのヌルテストがすべてのことです。 –

7

いずれのバージョンも、「threadsafe」の意味に依存して、スレッドセーフです。あなたの2番目のバージョンを検討してください:

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

"handler"は、不変の代理人を持ついくつかのフィールドのコピーです。 nullチェックの後、別のスレッドでフィールドが "null"に変更されたとします。その場合、元の非ヌル値のコピーを作成したため、コードはクラッシュしません。しかし、単にがクラッシュしても、はプログラムを作成しません。スレッドセーフです。クラッシュしないが間違った結果を生成するプログラムは、まだスレッドセーフではありません。

他のスレッドがイベントフィールドをnullに設定した場合、以前の内容が正しく動作するために必要な状態も変更されたとします。別のスレッドで突然変更された状態に依存するイベントハンドラを実行しようとしています。あなたは古くなったイベントハンドラを実行しています。

この問題から簡単に保護する方法はありません。それがあなたの状況だとすれば、状況に対処するためにあなたのスレッド論理を非常に慎重に設計しなければならなくなります。

関連する問題