7

私は同様の質問への回答を読んできましたが、まだ少し混乱しています...アベルには素晴らしい回答がありましたが、これは私が確信していない部分です:

...変数 volatile を宣言すると、アクセスごとに volatile になります。この動作を他の方法で強制することは不可能であるため、volatile を Interlocked に置き換えることはできません。これは、他のライブラリ、インターフェイス、またはハードウェアが変数にアクセスしていつでも更新できるシナリオ、または最新バージョンが必要なシナリオで必要になります。

Interlockedすべてのスレッドに対するアトミック操作の可視性は保証されますか?それとも、変更の可視性を保証するために値にキーワードを使用する必要がありvolatileますか?

これが私の例です:

volatile int value = 100000; // <-- do I need the volitile keyword
// ....

public void AnotherThreadMethod()
{
 while(Interlocked.Decrement(ref value)>0)
 {
  // do something
 }
}


public void AThreadMethod()
{
 while(value > 0)
 {
  // do something
 }
}

更新:
私はスポーツが苦手で、元の例を変更したので、ここにもう一度示します。

public class CountDownLatch
{
    private volatile int m_remain; // <--- do I need the volatile keyword here?
    private EventWaitHandle m_event;

    public CountDownLatch(int count)
    {
        Reset(count);
    }

    public void Reset(int count)
    {
        if (count < 0)
            throw new ArgumentOutOfRangeException();
        m_remain = count;
        m_event = new ManualResetEvent(false);
        if (m_remain == 0)
        {
            m_event.Set();
        }
    }

    public void Signal()
    {
        // The last thread to signal also sets the event.
        if (Interlocked.Decrement(ref m_remain) == 0)
            m_event.Set();
    }

    public void Wait()
    {
        m_event.WaitOne();
    }
}
4

2 に答える 2

6

インターロックされた変数の値をチェックしないため、ボラティリティは *必要ありません** 。代わりに、インターロックされた操作によって返される値を常に確認します。連動操作と通常の代入・比較を混在させると、常に不正なコードになります。

Reset() 関数の意図が何であるかはわかりませんが、そのコードはスレッド間プリミティブにはありません。m_remain に代入し、m_remain の値を直接チェックするのはかなり悪いことです。削除することを強くお勧めします: が正しく実装されていないだけでなく、寿命の途中にあるカウンターを「リセット」するセマンティクスが必要であることを強く疑っています。単純にしておきます: ctor (コードを Reset からそこに移動します) Signal と Wait は、必要な 3 つの演算子だけであり、現在のままで正しいものです。

コードを編集した後、更新されました。

2つを混ぜてはいけないという事実を無視して、それらを混ぜてしまった場合は、そうです、揮発性がまだ必要です。Volatile は、主に IL コードと生成された JIT コードに関するもので、値が常に実際のメモリ位置から読み取られ、コードの並べ替えなどの最適化が行われないようにします。無関係なコードがインターロック操作を使用して値を更新するという事実は、値を読み取る他の部分には影響しません。属性がない場合、コンパイラ/ JITvolatileは、書き込みがインターロックされているか、直接割り当てられているかどうかに関係なく、別の場所で発生した書き込みを無視するコードを生成する可能性があります。

ところで、通常の読み取り操作とインターロック操作を組み合わせた有効なパターンがありますが、通常は Interlocked.CompareExchange を含み、現在の状態を読み取り、現在の状態に基づいて計算を行い、状態をインターロックされた比較交換として置き換えようとします。成功した場合は問題なく、そうでない場合は計算結果を破棄してステップ 1 に戻ります。

于 2010-03-19T06:02:02.503 に答える
2

System.Threading.Thread.VolatileRead(ref myVariable) が探しているものかもしれません。Interlocked.Increment と組み合わせて使用​​すると、変更がアトミックであり、読み取った値が最新であることを保証できます。

于 2010-03-23T17:22:25.410 に答える