インターロッククラスを使用するために揮発性キーワードを使用するという利点はありますか?
-
19-09-2019 - |
質問
言い換えれば、通常の変数とインターロッククラスでも解決できない揮発性変数で何かをすることはできますか?
解決
編集:質問は主に書き直されています
この質問に答えるために、私はこの問題でもう少し飛び出し、いくつかのことを見つけました volatile
と Interlocked
私が気づいていなかったこと。私のためだけでなく、この議論や他の人々のためにこれを読んでいることを明確にしましょう。
volatile
読み取り/書き込みは、並べ替えの免疫があるはずです。これ それだけ 読み書きを意味します いいえ 他のアクションを意味します。- ボラティリティ CPU、つまりハードウェアレベルには強制されていません(x86は取得してフェンスをリリースします どれか 読み書き)。コンパイラやCLRの最適化を防ぎます。
Interlocked
CompareExchangeにアトミックアセンブリ命令を使用します(cmpxchg
)、増分(inc
)など;Interlocked
使用します 時々ロック:a マルチプロセッサシステムのハードウェアロック; Uni-Processor Systemsでは、ハードウェアロックはありません。Interlocked
とは異なりますvolatile
それはaを使用します フルフェンス, 、揮発性が半分のフェンスを使用しています。- 書き込み後の読み取りは並べ替えることができます 使用するとき
volatile
. 。それは起こりませんInterlocked
.VolatileRead
とVolatileWrite
「揮発性)と同じ並べ替えの問題があります(ブライアン・ギデオンのおかげでリンク)。
ルールができたので、あなたの質問に対する答えを定義できます。
- 技術的に:はい、あなたができることがあります
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
1つのアクセスごとに揮発性になります。この行動を他の方法で強制することは不可能です。volatile
置き換えることはできませんInterlocked
. 。これは、他のライブラリ、インターフェイス、またはハードウェアが変数にアクセスしていつでも更新できる、または最新のバージョンが必要なシナリオで必要です。
あなたが私に尋ねるなら、この最後のビットは実際の本当の必要性です volatile
また、2つのプロセスがメモリを共有し、ロックせずに読み書きが必要な場合に理想的にすることができます。変数を宣言します volatile
このコンテキストでははるかに安全です。その後、すべてのプログラマーが使用を強制します Interlocked
(これはコンパイラで強制することはできません)。
編集:次の引用は私の元の答えの一部でした、私はそれを残します;-)
からの引用 C#プログラミング言語 標準:
不揮発性フィールドの場合、順序付け命令が、順序付けが提供されているような同期なしでフィールドにアクセスするマルチスレッドプログラムで、予期しない予測不可能な結果につながる可能性があると考える最適化手法では ロックステートメント。これらの最適化は、コンパイラ、ランタイムシステム、またはハードウェアによって実行されます。揮発性フィールドの場合、そのような並べ替えの最適化は制限されています。
揮発性フィールドの読み取りはaと呼ばれます 揮発性読み取り. 。揮発性の読み取りには、次のことがあります。つまり、命令シーケンスでその後に発生するメモリへの参照の前に発生することが保証されています。
揮発性フィールドの書き込みはaと呼ばれます 揮発性書き込み. 。揮発性書き込みには「リリースセマンティクス」があります。つまり、命令シーケンスの書き込み命令の前に、メモリ参照の後に発生することが保証されています。
アップデート: 質問は主に書き直され、私の元の応答を修正し、「本当の」答えを追加しました
他のヒント
これはかなり複雑なトピックです。私はジョセフ・アルバハリを見つけます 書き上げる あなたの質問に答えるのに役立つかもしれない.NETフレームワークのマルチスレッド概念のより決定的で正確なソースの1つになること。
しかし、すぐに要約すると、 volatile
キーワードと Interlocked
それらを使用する方法に関するクラス。そしてもちろん、どちらも通常の変数でできることをはるかに超えています。
はい - 値を直接見ることができます。
インターロッククラスのみを使用して変数にアクセスする限り、違いはありません。何 揮発性 コンパイラに、変数が特別であり、最適化する場合は値が変更されていないと想定してはならないことをコンパイラに伝えます。
このループを取ります:
bool done = false;
...
while(!done)
{
... do stuff which the compiler can prove doesn't touch done...
}
設定した場合 done
に true
別のスレッドでは、ループが終了すると予想されます。ただし、完了した場合は、としてマークされていません volatile
その後、コンパイラには、ループコードが変更されないことを認識するオプションがあります done
また、出口の比較を最適化できます。
これは、マルチスレッドプログラミングに関する難しいことの1つです。問題である状況の多くは、特定の状況でのみ発生します。
はい、ロックの代わりに揮発性変数を使用してパフォーマンスを得ることができます。
ロックは、揮発性変数と他の多くの変数の同じ特性をあなたに与えることができる完全なメモリの障壁です。すでに言われているように、揮発性は、CPUがキャッシュラインの値を変更した場合、マルチスレッドシナリオでは、他のCPUがすぐに値を見ているが、ロックセマンティックを確保しないことを保証します。
ロックは揮発性よりもはるかに強力であり、不必要なロックを避けるためにできる限り揮発性を使用する必要があります。