メモリオーダリング
メモリオーダリング(英: Memory Ordering)とは、CPUによるコンピュータメモリへのアクセス順序を表わす。この言葉は、コンパイル時のコンパイラに生成されるメモリオーダリングか、実行時にCPUによって生成されるメモリオーダリングのいずれかを指す。
近代的なマイクロプロセッサでは、メモリオーダリングはメモリ操作の順番を入れ替えるCPUの特性を示す。メモリリオーダリングはアウト・オブ・オーダー実行の一種であり、キャッシュメモリやメモリバンクといった異なるタイプのメモリのバスを最大限に有効活用するために利用される。
現在のほとんどのユニプロセッサのメモリ操作は、プログラムコードで指定された順番では実行されない。シングルスレッドのプログラムでは、すべてのアウト・オブ・オーダー実行はプログラマから隠され、すべての命令は順番通りに実行されたように見える。しかしながら、マルチスレッド環境(もしくはメモリバスで他のハードウェアと接続されている場合)では、問題が起こりえる。この場合、問題を避けるためにはメモリバリアを使わなければならない。
WMOウィークメモリーオーダー (デフォルト) TSOトータルストアオーダー (Ztsoエクステンションでのみサポート)
コンパイラはこの特別な分割変換を許可していないため、sumのメモリ位置への唯一の書き込みは、value式の3つのポインタ読み取りに論理的に従わなければならない。
しかしプログラマが整数オーバーフローの目に見えるセマンティクスを気にして、このステートメントをプログラムレベルで次のように分割したとする。
最初のステートメントは、2つのメモリ読み込みをエンコードしており、これらは*sumへの最初の書き込みの前に(どちらかの順序で)行わなければならない。2つ目のステートメントは、*sumの2回目の更新に先立って、2つのメモリ読み込みを(どちらかの順序で)エンコードする。これにより、2つの加算処理の順序が保証されるが、アドレスエイリアシングという新たな問題が発生する可能性がある。つまり、これらのポインタのいずれもが同じメモリ位置を参照する可能性がある。
例えば、この例では*cと*sumが同じメモリロケーションにエイリアスされていると仮定し、両方のバージョンのプログラムを、*sumが両方の代わりになるように書き換えてみる。
これは何の問題もない。最初に*cと書いたものの元の値は*sumに代入された時点で失われ、*sumの元の値も失われるが、これは最初に上書きされたものなので、特に気にする必要はない。
これらのバリアは、コンパイラがコンパイル時に命令を入れ替えないように抑制する一方で、実行時のCPUによるリオーダリングを抑制することはできない。
GNUインラインアセンブラ命令
もしくは
は、GCCコンパイラが、その前後の読み書き命令を入れ替えることを禁止する。
Intel ECC compilerは"full compiler fence"な
という固有の機能を使う。
Microsoft Visual C++コンパイラには
が存在する。