10

.NET メモリ モデル (.NET Framework 上。compact/micro/silverlight/mono/xna/what-have-you ではない) では、特定の型 (特にプリミティブ整数と参照) の操作が保証されていることを知っています。アトミック。

さらに、x86/x64 の test-and-set 命令 (およびInterlocked.CompareExchange) は実際にはグローバル メモリの場所を参照しているため、成功すると別の命令Interlocked.CompareExchangeが新しい値を参照することになると思います。

最後に、volatileキーワードは、読み取りと書き込みをできるだけ早く伝達し、この変数に関する操作の順序を変更しないようにするためのコンパイラへの指示であると思います (右?)。

これにより、いくつかの疑問が生じます。

  1. 上記の私の信念は正しいですか?
  2. Interlocked.Readint のオーバーロードはなく、long (2 つの WORD であるため、通常はアトミックに読み取られません) のみです。.NET メモリ モデルでは、整数/参照を読み取るときに最新の値が表示されることが保証されていると常に想定していましたが、プロセッサ キャッシュやレジスタなどを使用すると、これが不可能になる可能性があることがわかり始めています。変数を強制的に再フェッチする方法はありますか?
  3. volatile は、整数と参照に関する上記の問題を解決するのに十分ですか?
  4. x86/x64では、それを想定できます...

2 つのグローバル整数変数 x と y があり、どちらも 0 に初期化されている場合、次のように記述します。

x = 1;
y = 2;

その NO スレッドは、x = 0 および y = 2 を認識します (つまり、書き込みは順番に発生します)。それらが揮発性である場合、これは変わりますか?

4

3 に答える 3

6
  • 最大で 32 ビット幅 (x64 システムでは 64 ビット幅) の変数への読み取りと書き込みのみがアトミックです。これが意味するのは、 intを読み取って半分書き込まれた値を取得しないということです。算術がアトミックであるという意味ではありません。
  • インターロックされた操作はメモリバリアとしても機能するため、はい、Interlocked.CompareExchange更新された値が表示されます。
  • このページを参照してください。揮発性とは、順序付けられたという意味ではありません。一部のコンパイラは、揮発性変数の操作を並べ替えないことを選択する場合がありますが、CPU は自由に並べ替えることができます。CPU による命令の並べ替えを停止する場合は、(フル) メモリ バリアを使用します。
  • メモリ モデルは、読み取りと書き込みがアトミックであることを保証し、volatile キーワードを使用すると、読み取りが常にレジスタからではなくメモリから行われることが保証されます。したがって、最新の値が表示されます。これは、x86 CPU が適切な場合にキャッシュを無効にするためです。これこれを参照してください。また、64 ビット値をアトミックに読み取る方法については、 InterlockedCompareExchange64を参照してください。
  • そして最後に、最後の質問です。答えは、スレッドが実際に と を見ることができるということx = 0ですy = 2。CPU は自由に命令を並べ替えることができるため、volatile キーワードを使用してもそれは変わりません。メモリバリアが必要です。

概要:

  1. コンパイラは命令を自由に並べ替えることができます。
  2. CPU は自由に命令を並べ替えることができます。
  3. ワードサイズの読み取りと書き込みはアトミックです。算術演算やその他の演算は、読み取り、計算、書き込みを伴うため、アトミックではありません。
  4. メモリからのワードサイズの読み取りでは、常に最新の値が取得されます。しかし、ほとんどの場合、実際にメモリから読んでいるかどうかはわかりません。
  5. 完全なメモリ バリアは、(1) と (2) を停止します。ほとんどのコンパイラでは、(1) を単独で停止できます。
  6. volatile キーワードを使用すると、メモリから読み取っていることが保証されます - (4)。
  7. インターロックされた操作 (lock プレフィックス) により、複数の操作をアトミックにすることができます。たとえば、読み取り + 書き込み (InterlockedExchange)。または、読み取り + 比較 + 書き込み (InterlockedCompareExchange)。それらはメモリバリアとしても機能するため、(1) と (2) は停止します。それらは常にメモリに(明らかに)書き込むため、(4)が保証されます。
于 2010-01-23T00:22:38.043 に答える
2

この古いスレッドに出くわしました。Hans と wj32 からの回答は、 に関する部分を除いてすべて正しいvolatileです。

具体的にはあなたの質問について

x86/x64 では、次のように仮定できます... 2 つのグローバル整数変数 x と y があり、両方とも 0 に初期化されている場合、次のように記述します。 x = 1; y = 2;

その NO スレッドは、x = 0 および y = 2 を認識します (つまり、書き込みは順番に発生します)。それらが揮発性である場合、これは変わりますか?

yが volatile である場合、 への書き込みxは への書き込みの前に発生することが保証されているため、およびyを参照するスレッドはありません。これは、volatile 変数への書き込みには「リリース セマンティック」(リリース フェンスの発行と論理的に同等) があるためです。つまり、移動しない前のすべての読み取り/書き込み命令はそれを渡します。(これは、x が揮発性であるが y がそうでない場合でも、予期しない and が表示される可能性があることを意味します。 ) 詳細については、 C# 仕様の説明とコード例を参照してください。 x = 0y = 2x = 0y = 2

于 2010-06-08T10:11:15.210 に答える
0

いいえ、volatile キーワードと原子性保証は弱すぎます。それを確実にするためにメモリバリアが必要です。Thread.MemoryBarrier() メソッドを使用して明示的に取得できます。

于 2010-01-20T10:49:07.063 に答える