言い換えれば、正規変数とInterlockedクラスでは解決できない揮発性変数を使用して何かを行うことはできますか?
5 に答える
編集:質問は大幅に書き直されました
この質問に答えるために、私は問題をもう少し掘り下げて、私が気付いていなかったいくつかvolatile
のことを見つけました。Interlocked
私だけでなく、この議論やこれについて読んでいる他の人々のために、それを明確にしましょう:
volatile
読み取り/書き込みは、並べ替えの影響を受けないはずです。これは読み取りと書き込みを意味するだけであり、他のアクションを意味するものではありません。- 揮発性はCPU、つまりハードウェアレベルに強制されません(x86は読み取り/書き込みで取得および解放フェンスを使用します)。コンパイラまたはCLRの最適化を防ぎます。
Interlocked
CompareExchange(cmpxchg
)、Increment(inc
)などのアトミックアセンブリ命令を使用します。Interlocked
時々ロックを使用します:マルチプロセッサシステムのハードウェアロック; ユニプロセッサシステムでは、ハードウェアロックはありません。Interlocked
volatileがハーフフェンスを使用するフルフェンスvolatile
を使用するという点で異なります。- を使用すると、書き込みに続く読み取りを並べ替えることができます
volatile
。では発生しませんInterlocked
。VolatileRead
`volatileとVolatileWrite
同じ並べ替えの問題があります(Brian Gideonに感謝します)。
ルールができたので、質問に対する答えを定義できます。
- 技術的には:はい、あなたができることと
volatile
できないことがありますInterlocked
:- 構文:
a = b
どこにa
またはb
揮発性であるかを書くことはできませんが、これは明らかです。 - 並べ替えのため、揮発性変数に書き込んだ後、別の値を読み取ることができます。でこれを行うことはできません
Interlocked
。言い換えれば、あなたはより安全性が低くなるvolatile
可能性がありますInterlocked
。 - パフォーマンス:
volatile
より高速Interlocked
です。
- 構文:
意味論的に:いいえ、
Interlocked
単に操作のスーパーセットを提供し、完全なフェンシングを適用するため、より安全に使用できるためです。あなたはあなたができないことで何もするvolatile
ことができません、Interlocked
そしてあなたは揮発性であなたがすることができないことで多くをすることができます:Interlocked
static volatile int x = 0; x++; // non-atomic static int y = 0; Interlocked.Increment(y); // atomic
スコープ:はい、変数を宣言する
volatile
と、アクセスごとに変数が揮発します。この動作を他の方法で強制することは不可能であるため、volatile
に置き換えることはできませんInterlocked
。これは、他のライブラリ、インターフェイス、またはハードウェアが変数にアクセスしていつでも更新できるシナリオ、または最新バージョンが必要なシナリオで必要になります。
私に言わせれば、この最後のビットは実際に必要volatile
なものであり、2つのプロセスがメモリを共有し、ロックせずに読み取りまたは書き込みを行う必要がある場合に理想的です。このコンテキストでは変数をvolatile
はるかに安全であると宣言してから、すべてのプログラマーに使用を強制しますInterlocked
(コンパイラーによって強制することはできません)。
編集:次の引用は私の元の答えの一部でした、私はそれを残します;-)
C#プログラミング言語標準からの引用:
不揮発性フィールドの場合、順序変更命令が、ロックステートメントによって提供されるような同期なしでフィールドにアクセスするマルチスレッドプログラムで予期しない予測できない結果をもたらす可能性があることを考慮する最適化手法。これらの最適化は、コンパイラ、ランタイムシステム、またはハードウェアによって実行できます。揮発性フィールドの場合、このような並べ替えの最適化は制限されています。
揮発性フィールドの読み取りは、揮発性読み取りと呼ばれます。揮発性読み取りには:acquireセマンティクスがあります。つまり、命令シーケンスでメモリへの参照の後に発生するメモリへの参照の前に発生することが保証されています。
揮発性フィールドの書き込みは、揮発性書き込みと呼ばれます。揮発性書き込みには「リリースセマンティクス」があります。つまり、命令シーケンスの書き込み命令の前のメモリ参照の後に発生することが保証されています。
更新:質問は大幅に書き直され、元の回答が修正され、「実際の」回答が追加されました
これはかなり複雑なトピックです。Joseph Albahariの記事は、あなたの質問に答えるのに役立つかもしれない.NETFrameworkのマルチスレッドの概念のより決定的で正確な情報源の1つであると思います。
しかし、簡単に要約すると、volatile
キーワードとInterlocked
クラスの間には、それらの使用方法に関して多くの重複があります。そしてもちろん、どちらも正規変数でできることをはるかに超えています。
はい-値を直接確認できます。
変数にアクセスするためにInterlockedクラスのみを使用する限り、違いはありません。volatileは、変数が特殊であり、最適化するときに値が変更されていないと想定してはならないことをコンパイラーに通知します。
このループを取ります:
bool done = false;
...
while(!done)
{
... do stuff which the compiler can prove doesn't touch done...
}
別のスレッドに設定done
するtrue
と、ループが終了することが期待されます。ただし、doneがマークされていない場合volatile
、コンパイラには、ループコードが変更されることはなくdone
、終了の比較を最適化できることを認識するオプションがあります。
これは、マルチスレッドプログラミングの難しい点の1つです。問題となる状況の多くは、特定の状況でのみ発生します。
はい、ロックの代わりに揮発性変数を使用することで、ある程度のパフォーマンスを得ることができます。
ロックは完全なメモリバリアであり、揮発性変数と同じ特性や他の多くの特性を提供できます。すでに述べたように、volatileは、マルチスレッドシナリオで、CPUがキャッシュラインの値を変更した場合に、他のCPUがその値をすぐに確認できるようにしますが、ロックセマンティクスをまったく保証しません。
ロックは揮発性よりもはるかに強力であり、不要なロックを回避できる場合は揮発性を使用する必要があります。