6

スレッドセーフでなければならないいくつかのコードがあり、その動作は次のようになります。


protected long m_RunningValue
protected long m_RunningCounter
protected object m_Lock = new object();

public long RunningValue { get { return Interlocked.Read(m_RunningValue); } }
public long RunningCounter { get { return Interlocked.Read(m_RunningCounter); } }

public void DoCalculation(int newValue, int newQuantity)
{
   lock(m_Lock)
   {
       Interlocked.Add(ref m_RunningValueA, newValue);
       Interlocked.Add(ref m_RunningCounter, newQuantity);
       if(Interlocked.Read(ref newQuantity) == 0)
       { 
         ...m_RunningValue gets further modified here
       }
   }
}

計算は値とカウンターの両方をロックする必要があります。そうしないと、競合状態が if(...) ブロックに影響を与える可能性がありますが、読み取り時に同期する必要はまったくありません。両方を読んでください。それは私にとって 100% 大丈夫です。

読み取りのインターロックは、64 ビット値のスレッドセーフ読み取りのためにあります。

  1. このようにインターロックとロックを混在させても安全ですか? 他の Web ページでそれらを混在させることは安全ではないことを読みましたが、これがそれらを混在させることが微妙なバグを導入するための優れた方法であることを意味するのか、またはシステムレベルでこれが関連するデータ構造を破損する可能性があるのか​​ を明確にすることはできません.

  2. このすべてのインターロック (64 ビット .NET 4.0 ランタイム) のコストは、プロパティ get() メソッドの周りの ReaderWriterSlim ロックを保存する目的を完全に無効にしますか?

4

1 に答える 1

5

編集されたバージョンに関しては、これはスレッドセーフであることが保証されていません。

32ビットプラットフォームを考えてみましょう。これは、64ビット長の値に2つの別々の操作でアクセスする必要があることを意味します。

1つのスレッドが数値の前半を読み取ってから、CPUからスワップオフされ、値の後半がその後ろで変更される可能性は十分にあります。これで、そのスレッドの値は完全に無効になります。

Interlocked.Readのドキュメントには、次のことが明示されています。

ReadメソッドとIncrement、Decrement、およびAddメソッドの64ビットのオーバーロードは、System.IntPtrが64ビットの長さのシステムでのみ真にアトミックです。他のシステムでは、これらのメソッドは相互にアトミックですが、データにアクセスする他の手段に関してはアトミックではありません。したがって、32ビットシステムでスレッドセーフにするには、Interlockedクラスのメンバーを介して64ビット値にアクセスする必要があります。

(強調鉱山)

編集:編集されたので、これは少しばかげているように見えますが、ある場所で連動しているが他の場所では連動していない場合は、意味がないことをここに残しておきます。

于 2010-12-07T23:45:15.733 に答える