| ナビゲーションリンクをスキップ | |
| 印刷ビューの終了 | |
|
Oracle Solaris Studio 12.3: C ユーザーガイド Oracle Solaris Studio 12.3 Information Library (日本語) |
コンパイラには、SPARC プロセッサと x86 プロセッサ用のさまざまなメモリーバリアー組み込み関数を定義する、ヘッダーファイル mbarrier.h が用意されています。これらの組み込み関数は、独自の同期プリミティブを使用してマルチスレッドコードを記述する開発者に役立つ場合があります。これらの組み込み関数がいつ必要になるか、また特定の状況で必要かどうかを判断するには、プロセッサのドキュメントを参照してください。
mbarrier.h によってサポートされるメモリーオーダリング組み込み関数を次に示します。
__machine_r_barrier() — これは、read バリアーです。これにより、バリアー前のすべてのロード操作が、バリアー後のすべてのロード操作の前に完了します。
__machine_w_barrier() — これは、write バリアーです。これにより、バリアー前のすべての格納操作が、バリアー後のすべての格納操作の前に完了します。
__machine_rw_barrier() — これは、read—write バリアーです。これにより、バリアー前のすべてのロードおよび格納操作が、バリアー後のすべてのロードおよび格納操作の前に完了します。
__machine_acq_barrier() — これは、acquire セマンティクスを持つバリアーです。これにより、バリアー前のすべてのロード操作が、バリアー後のすべてのロードおよび格納操作の前に完了します。
__machine_rel_barrier() — これは、release セマンティクスを持つバリアーです。これにより、バリアー前のすべてのロードおよび格納操作が、バリアー後のすべての格納操作の前に完了します。
__compiler_barrier() — コンパイラが、バリアーを越えてメモリーアクセスを移動しないようにします。
__compiler_barrier() 組み込み関数以外のバリアー組み込み関数はすべて、メモリーオーダリング命令を生成します。x86 プラットフォームの場合、これらは mfence、sfence、または lfence 命令です。SPARC プラットフォームの場合、これらは membar 命令です。
__compiler_barrier() 組み込み関数は、命令を生成せず、代わりに今後メモリー操作を開始する前にそれまでのメモリー操作をすべて完了する必要があることをコンパイラに通知します。実際の結果としては、局所でない変数と、static 記憶クラス指定子を持つ局所変数はすべて、バリアー前にメモリーに戻され、バリアー後に再ロードされます。コンパイラがバリアー前からのメモリー操作とバリアー後からのメモリー操作を混在させることはありません。ほかのすべてのバリアーには、__compiler_barrier() 組み込み関数の動作が暗黙的に含まれています。
次の例では、__compiler_barrier() 組み込み関数が存在しているため、コンパイラによる 2 つのループのマージが止まります。
#include "mbarrier.h"
int thread_start[16];
void start_work()
{
/* Start all threads */
for (int i=0; i<8; i++)
{
thread_start[i]=1;
}
__compiler_barrier();
/* Wait for all threads to complete */
for (int i=0; i<8; i++)
{
while (thread_start[i]==1){}
}
}