1

コードサンプル「方法:イベントアクセサメソッドの定義」

http://msdn.microsoft.com/en-us/library/dw1dtw0d.aspx

pEロックを取得せずに内部を変更しているように見えます。(問題を防ぐ魔法のようなことは何もしていないようDelegate::Combineです。)また、

void raise() {
   if (pE != nullptr)
      pE->Invoke();
}

これは、チェックとの間でpE変更した場合に問題になる可能性があります。2つの質問があります:nullInvoke()

  1. 既存のコードがスレッドセーフではないという点で私は正しいですか?

  2. スレッドセーフなバージョンのコードが必要なので、addremove関数をロックすることを考えていました。使用するのは時期尚早の最適化ですか

    void raise() {
        MyDel^ handler = pE;
        if (handler != nullptr)
           handler->Invoke();
    }
    

    または、その関数もロックする必要がありますか?

4

1 に答える 1

3

raiseリンクしたページの例とは異なり、3つのアクセサーはすべてデフォルトでスレッドセーフです(nullチェックを含み、競合状態を回避するためにローカル変数を使用します) 。

addカスタムイベントの実装に関しては、とremoveアクセサーを同期する必要があります。実装の周りにミューテックスを配置するだけです。ただし、演​​算子はデリゲートハンドルに対してオーバーロードされているため、呼び出しDelegate::Combineてからキャストすることで型の安全性を破棄する必要はありません。または、次のようにロックレスにすることができます。+-

void add(MyDel^ p)
{
     MyDel^ old;
     MyDel^ new;
     do {
         old = pE;
         new = pE + p;
     } while (old != Interlocked::CompareExchange(pE, new, old));
 }

必要な変更を加えて定義しますremovenew = pE - p;)。そして、あなたが提供したコードはraise、カスタムイベントの実装には完全に問題ありません。

要約すると、そのMSDNサンプルは完全なゴミです。そして、スレッドセーフを実現する最も簡単な方法は、自動実装されたイベントを使用することです。

于 2012-07-20T20:23:42.830 に答える