スレッド間のデータの受け渡し volatile編

mutexを使用したくない場合はvolatileを使用すること。
ただし、これはできるだけ使用しない方が良い。


volatileをできるだけ使用しない方が良い理由。
http://d.hatena.ne.jp/yupo5656/20040618/


http://www.linux.or.jp/JF/JFdocs/Parallel-Processing-HOWTO-2.html
ちょっと長いけれど引用する。

変数の保存のしかた

レジスタにある共有メモリのバッファされているオブジェクトの値を GCC が最適化しないようにするには、共有メモリ上のすべての実体を volatile という属性をつけて宣言する必要があります。こう宣言すると、共有するオブジェクトに対する 1 ワードだけのアクセスをともなう読み書きは、アトミックに行われます。例えば、p が整数へのポインタでポインタと整数両方が共有メモリにあるとすると、ANSI C での宣言は次のようになります。

volatile int * volatile p;

このコードでは、最初の volatile は int を参照し、その int は p を指しています。次の volatile は、ポインタそのものを参照しています。ややっこしいのですが、このちょっとした指定で、GCC があちこちで強力に最適化することが可能になります。少なくとも理屈上では、GCC に対して -traditional オプションをつけることで、最適化をいくぶん犠牲にして正しいコードを間違いなく生成できると思います。というのは、ANSI が定められる前の K&R の C は、そもそも register と意図的に指定をしない限り、すべての変数を volatile 扱いにしていました。GCCコンパイルする場合に cc -O6 ... という様にしているなら、本当に必要な部分にははっきりと volatile と指定したくなるに違いありません。

プロセッサのすべてのレジスタが更新されたことを知らせる役目であるアセンブリ言語のロックを使うと、GCC が適切にすべての変数をフラッシュして、 volatile と宣言したことに関連したコードが「非効率」にコンパイルされることを防ぐ、という噂があります。この裏技は、GCC のバージョン 2.7.0 を使って static で確保した外部変数に対して効果を発揮します…がこれは ANSI C 標準に沿った機能ではありませんし、なおまずいことに読み込みだけを行う他のプロセッサは、レジスタにずっと値をバッファしてしまいます。つまり、共有メモリ上の値が変更されていることを全く知りようがありません。まとめると、望みの動作を行うには volatile を使って変数にアクセスするしか正しく動作することが保証されない、ということです。

通常の変数に対して volatile 属性を指定してタイプキャストをすることで、volatile なアクセスが行えるということを理解しておいてください。例えば、通常の int i; は *((volatile int *) &i) とすることで、volatile に参照できるようになります。つまり、重要な部分に対してだけ「オーバーヘッド」をともなう volatile な操作を意図して呼び出すことができます。


つまり上記をまとめるとvolatileは重要な部分に対してだけ使用すること。
ただし、volatileは規格上はまずい。


個人的な経験ではvolatileよりもmutexの方が重い。