【シーエーエス】

CAS(コンペア・アンド・スワップ) とは?

最終更新:
💡 期待値なら更新する、不可分な比較と交換

メモリの値が期待値と一致したときだけ更新する比較・交換を、他のスレッドから不可分に見える操作として行う仕組み。原子性を保証するが、単一CPU命令や割り込み禁止を意味するわけではない。

📌 このページのポイント
CAS:期待値なら更新 整数のstrong CASの例 期待値 5 / 新しい値 6 値が一致 値が違う 5 7 5 → 6 に更新 7 のまま 成功を返す 失敗を返す 比較と条件付き更新は不可分 失敗後は最新の値で計算し直す
整数のstrong CASによる2つの場合。失敗しても更新対象は変えない。C++ではexpectedに比較時の値が入り、weakは値が等しくても失敗する場合がある。
ひよこ ひよこ
CASって何? ロックとは違うものなの?
ペンギン先生 ペンギン先生
Compare-And-Swapの略だよ。メモリの値が期待した値と同じときだけ更新し、その比較と更新を他のスレッドから不可分に見せる操作なんだ。単一のCPU命令に限らず、命令の組で実装する場合もある。割り込みを禁止するという意味ではないよ。
ひよこ ひよこ
普通に「読んで、比べて、書く」じゃだめなの?
ペンギン先生 ペンギン先生
それだと、比較してから書くまでの間に別のスレッドが値を書き換えるかもしれないよね。CASでは比較と条件付き更新が一体なので、その間に別の更新が入り込む隙間をなくせるんだ。
ひよこ ひよこ
比べて違っていたら、どうなるの?
ペンギン先生 ペンギン先生
更新対象には書き込まず、失敗を返すよ。ただしC++のcompare_exchangeでは、引数のexpectedには比較時に得た値が入る。それを使って新しい値を計算し直し、再試行するループがよく使われるんだ。競合が多ければ再試行も増えるよ。
ひよこ ひよこ
落とし穴はないの?
ペンギン先生 ペンギン先生
値がA→B→Aと戻ると、値だけの比較では途中の変化に気づけない。これがABA問題だよ。対策の一つは値と更新番号を一緒に比較・更新すること。全更新で番号を変える設計や番号の循環への配慮も必要で、番号を添えるだけで何でも解決するわけではないんだ。
ひよこ ひよこ
プログラミング言語ではどう書くの?
ペンギン先生 ペンギン先生
C++にはcompare_exchange_weakとcompare_exchange_strongがあるよ。weakは値が等しくても失敗する「偽の失敗」を許すので、通常は再試行ループで使う。ループ内で効率よく実装できる環境もあるけれど、常に速いとは限らないんだ。
もっと詳しく知りたい人へ

C++のatomicなら、必ずロックフリー?

必ずではないよ。型や実装によって異なり、is_lock_freeで確認できる。CASを使うだけでアルゴリズム全体の進行保証も決まらないんだ。操作の原子性とメモリの順序保証も別なので、共有データの受け渡しでは適切なメモリオーダーを選ぼう。

ペンギン
まとめ:ざっくりこれだけ覚えればOK!
「CAS」って出てきたら「期待した値なら更新する、不可分な比較・更新操作」と思えばだいたいOK!
📖 おまけ:英語の意味
「Compare-And-Swap」 = 比較して交換する(操作)
💬 Compare(比較)とSwap(交換)を1つの不可分な操作でやってしまうから、この名前だよ

参考資料

← 用語集にもどる