19

このオンラインブックによると、C#のvolatileキーワードは、書き込み操作の後に読み取り操作が続く順序を変更することを防ぎません。aこれは、とが次のように設定されているにもかかわらず、との両方bがに設定される可能性があるこの例を示しています。0xyvolatile

class IfYouThinkYouUnderstandVolatile
{
  volatile int x, y;
 
  void Test1()        // Executed on one thread
  {
    x = 1;            // Volatile write (release-fence)
    int a = y;        // Volatile read (acquire-fence)
    ...
  }
 
  void Test2()        // Executed on another thread
  {
    y = 1;            // Volatile write (release-fence)
    int b = x;        // Volatile read (acquire-fence)
    ...
  }
}

これは、仕様が10.5.3で述べていることと一致しているようです。

揮発性フィールドの読み取りは、揮発性読み取りと呼ばれます。揮発性読み取りには「取得セマンティクス」があります。つまり、命令シーケンスでメモリへの参照の後に発生するメモリへの参照の前に発生することが保証されています。

揮発性フィールドの書き込みは、揮発性書き込みと呼ばれます。揮発性書き込みには「リリースセマンティクス」があります。つまり、命令シーケンスの書き込み命令の前のメモリ参照の後に発生することが保証されています。

これの理由は何ですか?書き込みと読み取りの操作が並べ替えられてもかまわないユースケースはありますか?

4

3 に答える 3

7

Volatileは、独立した揮発性変数の読み取りと書き込みが並べ替えられないことを保証するものではなく、読み取りが最新の値(キャッシュされていない)を取得することを保証するだけです。(単一の変数の読み取りと書き込みは、順序を維持することが保証されています)

http://msdn.microsoft.com/en-us/library/x13ttww7%28v=vs.71%29.aspx

前の命令が同じオブジェクトから値を要求した場合でも、システムは常に、要求された時点で揮発性オブジェクトの現在の値を読み取ります。また、オブジェクトの値は割り当て直後に書き込まれます。

volatile修飾子は通常、アクセスをシリアル化するためにlockステートメントを使用せずに複数のスレッドによってアクセスされるフィールドに使用されます。volatile修飾子を使用すると、あるスレッドが別のスレッドによって書き込まれた最新の値を確実に取得できます。

複数の依存操作がある場合は常に、他の同期メカニズムを使用する必要があります。通常はを使用しますlock。これは最も簡単で、悪用された場合や非常に極端な状況でのみパフォーマンスのボトルネックを引き起こします。

于 2012-07-31T20:30:49.833 に答える
4

x86 / x64アーチでは、並べ替えによる防止volatile writeにはかなりの費用がかかります。volatile readこれは、と呼ばれる書き込み最適化のためですstore buffers。Javaはこのように進んでおり、Javaでの揮発性書き込みは、CPU命令レベルで事実上完全なメモリバリアです。

于 2016-07-15T16:19:22.563 に答える
3

多分答えるには遅すぎます...しかし私は周りを見回してこれを見ました。Volatile-readは、実際には次のようなメソッドの呼び出しです。

public static int VolatileRead(ref int address)
{
    int num = address;
    Thread.MemoryBarrier();
    return num;
}

そして、Volatile-writeは次のようになります。

public static int VolatileWrite(ref int address, int value)
{
    Thread.MemoryBarrier();
    adrdress = value;
}

命令MemoryBarrier();は、並べ替えを防ぐものです。MemoryBarrier();前の命令が後の命令の前に実行されることを保証します。VW、VRの場合、次のようになります。

Thread.MemoryBarrier();
adrdress = value; //this line may be reordered with the one bellow
int num = address;//this line may be reordered with the one above
Thread.MemoryBarrier();
return num;
于 2015-11-16T14:46:59.000 に答える