15

volatileC/C++ では脆弱であり、複数のプロセッサでの同時実行環境で問題が発生する可能性があると言及している多くの参考文献で見つけましたがvolatile、C#/Java では異なる CPU 間の通信メカニズムとして使用できます ( )。このキーワードは、C/C++ よりも C#/Java の方が厳密なようですが、それらの違いや影響は何ですか?

これはvolatileC/C++ のリファレンスです。 マルチスレッドの C または C++ プログラミングで volatile が有用と見なされないのはなぜですか?

4

3 に答える 3

17

C#/Javaの場合、 " volatile" は、変数の値がプログラム自体のスコープ外で変更される可能性があるため、変数の値を決してキャッシュしてはならないことをコンパイラーに伝えます。コンパイラは、変数が「制御外」に変更された場合に問題を引き起こす可能性のある最適化を回避します。

C/C++ ではvolatileメモリ マップド ハードウェア デバイスの読み取りまたは書き込みが必要な組み込みシステムまたはデバイス ドライバーを開発するときに " " が必要です。特定のデバイス レジスタの内容はいつでも変更される可能性があるvolatileため、そのようなアクセスがコンパイラによって最適化されないようにするには、" " キーワードが必要です。

于 2013-11-12T07:35:08.487 に答える
11

volatile キーワードは、言語とそれが実装されているプラ​​ットフォームに対して非常に主観的です。Java はすべてのアーキテクチャで volatile の一貫した動作を提供しますが、これは、C/C++ の場合のように、ネイティブ マシン プラットフォームに直接コンパイルされる言語には当てはまりません。なぜそうなのかを理解しようとしましょう。

a、b を一連のプログラム アクション P のメンバーとし、v_{n} (a) をアクションにボラティリティ要件を適用する関数とします。ここで、添え字 _n は揮発性アクションが適用される _n 回目の繰り返しを示します。 、および \rightarrow は前に説明した先行演算子です。すべてのプログラム アクションについて、次のルールが適用されます。

v_n(a) \rightarrow v_{n+1}(a)

a \rightarrow v_n(b) \Rightarrow a \rightarrow v_{n+i}(b) ここで、i \in \mathbb{N}

ルール 1 は、すべての揮発性関数が全体的な順序を強制することを示しています。ここで、関数 v_{n} (a) は常に v_{n+1} (a) に先行します。ルール 2 は、アクション a がアクションの揮発性関数に先行する場合、 _n 回目の反復で b を実行する場合、アクション a は、b に適用される後続のすべての揮発性関数より必ず先行する必要があります。

これは Java では非常に強力なメモリ要件であり、実際には C/C++ と比較してはるかに強力です。C/C++ 言語仕様には、メモリの順序付けに関するこのような制限はなく、揮発性アクションの周囲で不揮発性アクションをどのように順序付けるかは、コンパイラの実装に委ねられています。

簡単なコード サンプルを使用して、これらの規則がプログラムの実行にどのように影響するかを考えてみましょう。

int a = 0;
int b = 0;
volatile int count = 0;

a  = 1;
count = 1;
b = 2;
count = 2;

C/C++ では、volatile キーワードは、count 変数が相互に並べ替えられないことのみを保証します。count == 2 の場合、必ず count = 1 が先行する必要があります。ただし、a == 1 であるという保証も、b == 2 であるという保証もありません。

Java では、上記で定義されたより強力な保証が与えられた場合、count == 1 の場合、アサーション a == 1 は真でなければなりません。同様に、count == 2 の場合、a == 1 && b == 2 が真でなければならないというアサーション。これは、C/C++ が提供しない Java の厳密なメモリ保証が意味するものです。

ただし、これは、C/C++ が Java と同じように動作しないという意味ではありません。そうするかどうかは、(1) コンパイラが、驚くべき順序ではあるが正当な順序でコードの並べ替えを実行するかどうか、および (2) 基礎となるマシン アーキテクチャが同じ厳密なメモリ順序を維持するかどうかに依存します。コンパイラは、驚くべきコードの並べ替えを実行しません。

たとえば、すべての x86 プラットフォームで -O0 を設定して gcc でコードをコンパイルすると、Java のメモリ モデルに準拠します (より厳密になります)。プログラマーが予期しない動作。警告レクター!

いずれにせよ、メモリ モデルの整合性規則の詳細に興味がある場合は、x86 メモリ モデルに関する Intel の説明をご覧になることをお勧めします。ここでは、メモリの順序付けのニュアンスが詳細に説明されています。楽しみ!

于 2013-11-12T07:44:18.637 に答える
4

C/C++ では、volatileマルチスレッドに関連する特定のセマンティクスがないため、そのコンテキストでの動作はプラットフォーム固有です。C# と Java は、特定のマルチスレッド セマンティクスを提供しvolatileます。そのため、何が得られているかを把握し、信頼することができます。

于 2013-11-12T07:32:54.720 に答える