私はC++アプリを書いています。
複数のスレッドが書き込んでいるクラス変数があります。
C++ では、変更されていることをコンパイラが「認識」せずに変更できるものはすべて、揮発性とマークする必要がありますよね? 私のコードがマルチスレッド化されていて、あるスレッドが var に書き込み、別のスレッドがそれから読み取る場合、var volaltile をマークする必要がありますか?
[アトミックな int への書き込みに依存しているため、競合状態はありません]
ありがとう!
C++ にはまだマルチスレッドの準備が整っていません。実際には、揮発性はあなたが意味することをしません(これはメモリアドレス指定のハードウェア用に設計されており、2つの問題は似ていますが、揮発性が正しいことをしないほど十分に異なっています-揮発性は他の用途で使用されていることに注意してくださいmt コンテキストで使用するための言語)。
したがって、あるスレッドでオブジェクトを書き込み、別のスレッドでそれを読み取りたい場合は、必要なときに実装に必要な同期機能を使用する必要があります。私が知っている人にとって、揮発性はその中で何の役割も果たしません。
参考までに、次の標準では MT が考慮され、volatile はその役割を果たしません。それで変わりません。同期が必要な標準定義の条件と、それらを達成するための標準定義の方法があります。
volatile は、「外部から」最適化される可能性があるため、変数値または使用法の「直感」に基づいて最適化しないようにコンパイラーに指示します。
volatile は同期を提供しませんが、 int への書き込みがアトミックであるという仮定はほとんど現実的です!
あなたのケースで volatile が必要かどうか (またはプログラムの動作をチェックするかどうか) を知るために、またはさらに重要なことに、何らかの同期が見られる場合は、いくつかの使用法を確認する必要があると思います。
volatile
これは読み取り、特にメモリ マップド I/O レジスタの読み取りにのみ当てはまると思います。
これを使用して、メモリ位置から読み取った後は値が変更されないと想定しないようにコンパイラに指示できます。
while (*p)
{
// ...
}
上記のコードで*p
は、 がループ内に書き込まれていない場合、コンパイラは読み取りをループの外に移動することを決定する可能性があります。
cached_p=*p
while (cached_p)
{
// ...
}
がメモリ マップド I/O ポートへのポインタである場合p
、毎回ループに入る前にポートがチェックされる最初のバージョンが必要です。
がマルチスレッド アプリのメモリへのポインターである場合p
でも、書き込みがアトミックであるとは限りません。
ロックしないと、コンパイラまたはプロセッサによって「不可能な」並べ替えが行われる可能性があります。また、int への書き込みがアトミックであるという保証はありません。
適切なロックを使用することをお勧めします。
揮発性はあなたの問題を解決します。システムのすべてのキャッシュ間で一貫性が保証されます。ただし、R または W アクセスごとにメモリ内の変数を更新するため、非効率的です。代わりに、必要なときだけメモリバリアを使用することを検討してください。作業している場合、または gcc/icc で同期ビルトインを調べている場合: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html
編集(主にpm100コメントについて):私の信念は参考にならないことを理解しているので、引用するものを見つけました:)
volatile キーワードは、特定の非同期イベントが存在する場合にコードが正しく表示されない可能性があるコンパイラの最適化を防ぐために考案されました。たとえば 、プリミティブ変数を volatile として宣言した場合、コンパイラはそれをレジスタにキャッシュできません。
ドブ博士より
もっと面白い :
揮発性フィールドは線形化可能です。volatile フィールドの読み取りは、ロックの取得に似ています。ワーキング メモリが無効になり、volatile フィールドの現在の値がメモリから再読み取りされます。揮発性フィールドへの書き込みは、ロックの解放に似ています。揮発性フィールドはすぐにメモリに書き戻されます。 (これは一貫性に関するものであり、原子性に関するものではありません)
The Art of multiprocessor programmingより、Maurice Herlihy & Nir Shavit
ロックにはメモリ同期コードが含まれています。ロックしない場合は、何かを行う必要があり、volatile キーワードを使用するのがおそらく最も簡単なことです (メモリがアドレス空間にバインドされた外部デバイス用に設計されていたとしても、それは重要ではありません)。ここ)