【メモリバリア】

メモリバリア とは?

最終更新:
💡 メモリの読み書きに、守るべき順序を作る境界

メモリの読み書きについて、特定の前後関係を守るための仕組み。CPUやコンパイラによる順序の入れ替えを制約する。メモリフェンスとも呼ばれる。

📌 このページのポイント
読み書きの順序を、対応する同期で守る C++の例:atomicなflag、初期値0書き込み側 A読み取り側 B① data = 42② flagに1を保存release③ flagを読むacquire④ dataを読む③が②の1を受け取った場合、④は42を読めるdataは一度だけ公開し、その後は書き換えないrelaxedだけでは、この公開を同期しない
矢印は各スレッドの順序とflagの受け渡し。生のバリア命令ではなく、atomic操作による同期の例。
ひよこ ひよこ
メモリバリアって何? 何を邪魔する壁なの?
ペンギン先生 ペンギン先生
読み書きに必要な順序を守る仕組みだよ。CPUやコンパイラは、単独のスレッドの動作を保つ範囲で処理を並べ替えられる。でも別のスレッドからは、その並びのまま見えるとは限らない。バリアは、種類に応じた前後関係を制約するんだ。
ひよこ ひよこ
順序が入れ替わると何が困るの?
ペンギン先生 ペンギン先生
Aがdataを書いてから準備完了のflagを公開し、Bがflagを見てdataを読む例を考えよう。適切な同期がなければ、準備完了を見たからdataも読める、とは保証できない。C++では普通の変数を同期なしに読み書きするとデータ競合で未定義動作になり、古い値が見えるだけでは済まないよ。
ひよこ ひよこ
バリアを置けば、処理が全部終わるの?
ペンギン先生 ペンギン先生
それとは違うよ。バリアは主に順序を制約するもので、すべての読み書きの完了や、ほかのスレッドの停止を保証するものではないんだ。共有データを同時に触らせないmutexなどの排他制御とも役割を区別しよう。
ひよこ ひよこ
releaseとacquireはどう組み合わせるの?
ペンギン先生 ペンギン先生
C++なら、Aがdataを書いた後、atomicなflagに1をreleaseで保存する。Bが同じflagをacquireで読み、その保存した1を受け取れば、先行するdataの書き込みを観測できるよ。dataをその後に書き換えないなど、別のデータ競合がないことも前提なんだ。
ひよこ ひよこ
CPUごとに同じ命令を使うの?
ペンギン先生 ペンギン先生
必要な命令や保証はCPUや実行環境によって異なるよ。コンパイラの並べ替えを抑える仕組みと、CPUのメモリ順序を制約する命令も区別が必要だね。C++の通常のスレッド間通信では、CPU命令を直接足すより、言語が定めるatomicやmutexの同期規則に沿って設計するんだ。
もっと詳しく知りたい人へ

バリアを1つ置けば安全になりますか?

なりません。図はC++のatomic操作でdataを一度だけ公開する例です。flagは初期値0で、読み取り側がrelease保存した1をacquireで受け取り、その後dataに別の書き込みがないことが前提です。relaxedはflag自身の原子性を保ちますが、別のdataの公開を同期しません。

ペンギン
まとめ:ざっくりこれだけ覚えればOK!
「メモリバリア」って出てきたら「メモリの読み書きに必要な順序を守る境界」と思えばだいたいOK!
📖 おまけ:英語の意味
「Memory Barrier」 = メモリの障壁。Memory Fenceとも呼ばれる
💬 Barrierは障壁、Fenceは柵という意味だよ。境界をまたぐ読み書きの順序を制約するイメージで捉えよう。

参考資料

← 用語集にもどる