C/Pthreads の使用:共有変数は揮発性である必要がありますか?

ロックを使用して変数へのアクセスを制御している限り、変数に volatile は必要ありません。実際、変数に volatile を設定している場合は、おそらく既に間違っています。

https://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/


答えは絶対に、明確に、NOです。適切な同期プリミティブに加えて「volatile」を使用する必要はありません。実行する必要があるすべてのことは、これらのプリミティブによって実行されます。

「揮発性」の使用は必要でも十分でもありません。適切な同期プリミティブで十分なので、必要ありません。噛み付く可能性のあるすべての最適化ではなく、一部の最適化のみを無効にするため、十分ではありません。たとえば、原子性や別の CPU での可視性は保証されません。

その通りですが、揮発性を使用したとしても、CPU は自由に共有データを書き込みポスティング バッファに任意の時間キャッシュできます。あなたを噛む可能性のある最適化のセットは、「揮発性」が無効にする最適化のセットと正確には同じではありません。したがって、「揮発性」を使用すると、 盲目的な運に頼っています。

一方、定義済みのマルチスレッド セマンティクスで同期プリミティブを使用すると、動作が保証されます。プラスとして、「volatile」によるパフォーマンスへの大きな影響を受けません。では、なぜそのようにしないのでしょうか?


volatile の非常に重要なプロパティの 1 つは、変数が変更されたときにメモリに書き込まれ、アクセスするたびにメモリから再読み取りされることだと思います。ここでの他の回答では、揮発性と同期が混在しています。これ以外のいくつかの回答から、揮発性が同期プリミティブではないことは明らかです(クレジットが必要な場合はクレジット)。

ただし、volatile を使用しない限り、コンパイラは共有データをレジスタに自由にキャッシュできます。コンパイラの裁量で、揮発性としてマークする必要があります。または、共有データを変更する関数を終了した後にのみ共有データにアクセスする場合は、問題ない可能性があります。しかし、値がレジスタからメモリに書き戻されることを確認するために、運に頼らないことをお勧めします。

特に、レジスタが豊富なマシン (つまり、x86 ではない) では、変数はレジスタ内に非常に長い期間存在する可能性があり、優れたコンパイラは、構造体の一部または構造体全体をレジスタにキャッシュすることもできます。したがって、揮発性を使用する必要がありますが、パフォーマンスのために、計算のために値をローカル変数にコピーしてから、明示的な書き戻しを行います。基本的に、volatile を効率的に使用するということは、C コードでロードストアの考え方を少し行うことを意味します。

いずれにせよ、正しいプログラムを作成するには、OS レベルで提供されるある種の同期メカニズムを積極的に使用する必要があります。

volatile の弱点の例については、私の Decker のアルゴリズムの例 (http://jakob.engbloms.se/archives/65) を参照してください。これは、volatile が同期に機能しないことをよく証明しています。