キーワード volatile はマルチスレッド プログラミングに適しているという考えが広まっています。
Hans Boehmは、volatile の移植可能な用途は 3 つしかないことを指摘しています。
- volatileを使用して、longjmp 全体で値を保持する必要がある setjmp と同じスコープ内のローカル変数をマークすることができます。問題のローカル変数を共有する方法がない場合、アトミック性と順序付けの制約は効果がないため、そのような使用のどの部分が遅くなるかは不明です。(すべての変数を longjmp 全体で保存することを要求することによって、そのような使用のどの部分が遅くなるかは不明ですが、それは別の問題であり、ここでは考慮されません。)
- volatileは、変数が「外部的に変更される」可能性がある場合に使用できますが、実際には変更はスレッド自体によって同期的にトリガーされます。たとえば、基になるメモリが複数の場所にマップされているためです。
- volatile sigatomic_tは、制限された方法で、同じスレッド内のシグナル ハンドラーと通信するために使用できます。sigatomic_t ケースの要件を緩和することを検討することもできますが、それはかなり直感に反するようです。
速度のためにマルチスレッドを使用している場合、コードを遅くすることは絶対に望んでいないことです。マルチスレッド プログラミングの場合、volatile が対処すると誤って考えられることが多い 2 つの重要な問題があります。
- 原子性
- メモリの一貫性、つまり、別のスレッドから見たスレッドの操作の順序。
まずは(1)から。Volatile は、アトミックな読み取りまたは書き込みを保証しません。たとえば、129 ビット構造の揮発性の読み取りまたは書き込みは、ほとんどの最新のハードウェアではアトミックではありません。32 ビット int の volatile 読み取りまたは書き込みは、ほとんどの最新のハードウェアではアトミックですが、volatile はそれとは何の関係もありません。揮発性がなければアトミックになる可能性があります。原子性はコンパイラの気まぐれです。C または C++ の標準には、アトミックでなければならないという規定はありません。
ここで問題 (2) を考えます。プログラマーは、volatile を volatile アクセスの最適化をオフにするものと考えることがあります。それは実際にはほとんど真実です。しかし、それは揮発性アクセスのみであり、不揮発性アクセスではありません。次のフラグメントを検討してください。
volatile int Ready;
int Message[100];
void foo( int i ) {
Message[i/10] = 42;
Ready = 1;
}
マルチスレッド プログラミングで非常に合理的なことをしようとしています。つまり、メッセージを書き込んでから別のスレッドに送信します。もう一方のスレッドは、Ready がゼロ以外になるまで待機してから、Message を読み取ります。gcc 4.0 または icc を使用して "gcc -O2 -S" でこれをコンパイルしてみてください。どちらも Ready へのストアを最初に行うため、i/10 の計算と重複する可能性があります。並べ替えはコンパイラのバグではありません。それはその仕事をしている積極的なオプティマイザです。
解決策は、すべてのメモリ参照を揮発性とマークすることだと思うかもしれません。それはただのばかげたことです。前の引用が言うように、それはあなたのコードを遅くするだけです. 最悪の場合、問題が解決しない可能性があります。コンパイラが参照を並べ替えなくても、ハードウェアが並べ替える可能性があります。この例では、x86 ハードウェアはそれを並べ替えません。Itanium コンパイラは揮発性ストアにメモリ フェンスを挿入するため、Itanium(TM) プロセッサもそうではありません。これは賢い Itanium 拡張です。しかし、Power(TM) のようなチップは再注文します。順序付けに本当に必要なのは、メモリ バリアとも呼ばれるメモリ フェンスです。メモリ フェンスは、フェンスを越えたメモリ操作の並べ替えを防ぎます。場合によっては、一方向の並べ替えを防ぎます。揮発性はメモリ フェンスとは関係ありません。
では、マルチスレッド プログラミングの解決策は何でしょうか? アトミックおよびフェンス セマンティクスを実装するライブラリまたは言語拡張機能を使用します。意図したとおりに使用すると、ライブラリ内の操作によって適切なフェンスが挿入されます。いくつかの例:
- POSIX スレッド
- Windows(TM) スレッド
- OpenMP
- 未定
Arch Robison (Intel) の記事に基づく