8

言い換えれば、正規変数とInterlockedクラスでは解決できない揮発性変数を使用して何かを行うことはできますか?

4

5 に答える 5

17

編集:質問は大幅に書き直されました

この質問に答えるために、私は問題をもう少し掘り下げて、私が気付いていなかったいくつかvolatileのことを見つけました。Interlocked私だけでなく、この議論やこれについて読んでいる他の人々のために、それを明確にしましょう:

  • volatile読み取り/書き込みは、並べ替えの影響を受けないはずです。これは読み取りと書き込みを意味するだけであり、他のアクションを意味するものではありません。
  • 揮発性はCPU、つまりハードウェアレベルに強制されません(x86は読み取り/書き込みで取得および解放フェンスを使用します)。コンパイラまたはCLRの最適化を防ぎます。
  • InterlockedCompareExchange(cmpxchg)、Increment(inc)などのアトミックアセンブリ命令を使用します。
  • Interlocked 時々ロックを使用します:マルチプロセッサシステムのハードウェアロック; ユニプロセッサシステムでは、ハードウェアロックはありません。
  • Interlockedvolatileがハーフフェンスを使用するフルフェンスvolatileを使用するという点で異なります。
  • を使用すると、書き込みに続く読み取りを並べ替えることができますvolatile。では発生しませんInterlockedVolatileRead`volatileとVolatileWrite同じ並べ替えの問題があります(Brian Gideonに感謝します)。

ルールができたので、質問に対する答えを定義できます。

  • 技術的には:はい、あなたができることとvolatileできないことがありますInterlocked
    1. 構文:a = bどこにaまたはb揮発性であるかを書くことはできませんが、これは明らかです。
    2. 並べ替えのため、揮発性変数に書き込んだ後、別の値を読み取ることができます。でこれを行うことはできませんInterlocked。言い換えれば、あなたはより安全性が低くなるvolatile可能性がありますInterlocked
    3. パフォーマンス: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セマンティクスがあります。つまり、命令シーケンスでメモリへの参照の後に発生するメモリへの参照の前に発生することが保証されています。

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

更新:質問は大幅に書き直され、元の回答が修正され、「実際の」回答が追加されました

于 2009-11-09T14:27:29.160 に答える
1

これはかなり複雑なトピックです。Joseph Albahariの記事は、あなたの質問に答えるのに役立つかもしれない.NETFrameworkのマルチスレッドの概念のより決定的で正確な情報源の1つであると思います。

しかし、簡単に要約すると、volatileキーワードとInterlockedクラスの間には、それらの使用方法に関して多くの重複があります。そしてもちろん、どちらも正規変数でできることをはるかに超えています。

于 2009-11-09T14:27:47.583 に答える
0

はい-値を直接確認できます。

変数にアクセスするためにInterlockedクラスのみを使用する限り、違いはありません。volatileは、変数が特殊であり、最適化するときに値が変更されていないと想定してはならないことをコンパイラーに通知します。

このループを取ります:

bool done = false;

...

while(!done)
{
... do stuff which the compiler can prove doesn't touch done...
}

別のスレッドに設定doneするtrueと、ループが終了することが期待されます。ただし、doneがマークされていない場合volatile、コンパイラには、ループコードが変更されることはなくdone、終了の比較を最適化できることを認識するオプションがあります。

これは、マルチスレッドプログラミングの難しい点の1つです。問題となる状況の多くは、特定の状況でのみ発生します。

于 2009-11-09T14:27:04.003 に答える
0

私はこのテーマの権威になるつもりはありませんが、自慢のジョン・スキートによるこの記事をご覧になることを強くお勧めします。

また、この回答の最後の部分で、何volatileに使用すべきかを詳しく説明しています。

于 2009-11-09T14:29:06.987 に答える
-1

はい、ロックの代わりに揮発性変数を使用することで、ある程度のパフォーマンスを得ることができます。

ロックは完全なメモリバリアであり、揮発性変数と同じ特性や他の多くの特性を提供できます。すでに述べたように、volatileは、マルチスレッドシナリオで、CPUがキャッシュラインの値を変更した場合に、他のCPUがその値をすぐに確認できるようにしますが、ロックセマンティクスをまったく保証しません。

ロックは揮発性よりもはるかに強力であり、不要なロックを回避できる場合は揮発性を使用する必要があります。

于 2009-11-09T14:44:57.387 に答える