1. ホーム
  2. c++

[解決済み] なぜvolatileはマルチスレッドのCやC++のプログラミングで有用ではないと考えられているのですか?

2022-04-22 13:43:40

質問

で示したように この回答 先日投稿した、実用性(またはその欠如)について混乱しているようです。 volatile マルチスレッドプログラミングのコンテキストで

私の理解では、変数にアクセスするコードの制御の流れの外で変数が変更される可能性がある場合は、その変数は、以下のように宣言する必要があります。 volatile . シグナルハンドラ、I/Oレジスタ、他のスレッドによって変更された変数などは、すべてこのような状況に該当します。

つまり、もしグローバルな int foo であり、かつ foo があるスレッドによって読み込まれ、別のスレッドによって(おそらく適切な機械命令を使って)アトミックに設定された場合、読み込んだスレッドはこの状況を、シグナルハンドラによって調整された変数や外部のハードウェア条件によって変更された変数を見るのと同じように見て、その結果 foo を宣言する必要があります。 volatile (または、マルチスレッド環境では、メモリフェンシングロードでアクセスするのがより良い解決策でしょう)。

どこがどう間違っているのでしょうか?

どうすればいい?

の問題は volatile をマルチスレッドコンテキストで提供しないことです。 すべて を保証するものです。必要なプロパティはいくつかありますが、全てではありません。 volatile 単独 .

しかし、そのために使わなければならないプリミティブは 残り プロパティが提供するものも volatile が行うので、事実上不要です。

共有データへのスレッドセーフなアクセスには、次のような保証が必要です。

  • 読み書きが実際に行われること(コンパイラが値をレジスタに格納し、メインメモリの更新をずっと後まで延期することはないこと)
  • 並べ替えが行われないこと。仮に volatile このフラグは、あるデータが読み込める状態にあるかどうかを示すものである。このコードでは、データを準備した後にフラグをセットするだけなので、すべての ルックス となります。しかし、もし命令の順番を変えて、フラグがセットされるようにしたらどうでしょう 最初 ?

volatile は、最初の点を保証しています。また、並べ替えが発生しないことも保証しています。 異なる揮発性の読み取り/書き込みの間 . すべて volatile のメモリアクセスは、指定された順番で発生します。これだけで、何のために volatile は、I/O レジスタやメモリマップド・ハードウェアを操作するためのものですが、マルチスレッドコードで volatile オブジェクトは、しばしば不揮発性データへのアクセスを同期させるためにのみ使用されます。これらのアクセスは、まだ volatile のものがあります。

並べ替えを防止するための解決策としては メモリバリア ということをコンパイラとCPUの両方に示します。 このポイントでは、メモリアクセスの順序を変更することはできません。 . このようなバリアを揮発性変数アクセスの周囲に置くことで、不揮発性アクセスも揮発性変数に順番が入れ替わることがなくなり、スレッドセーフなコードを書くことができるようになります。

ただし、メモリバリア また は、バリアに到達したときに保留中のすべての読み取り/書き込みが実行されることを保証するため、それだけで必要なものを効果的に提供し volatile は不要です。このまま volatile という修飾子があります。

C++11以降、アトム変数( std::atomic<T> によって、関連するすべての保証が得られます。