読者です 読者をやめる 読者になる 読者になる

Pebble's Diary

プログラマーの作業メモ

atomic::compare_exchange_weak C++11

C++11
bool compare_exchange_weak (T& expected, T val, memory_order sync = memory_order_seq_cst) noexcept;

compare_exchange_weakの動作仕様がいつまでも覚えられないので、メモ。
覚える必要があるのは第一引数と第二引数と戻り値。
メモリオーダーはとりあえず無視して良い。
以下2つの動作仕様を覚えよう。
(A1) std::atomicインスタンスの値が、expectedの場合、インスタンスの値をvalの値に変更する。
この時の戻り値はtrue。
(A2) インスタンスの値がexpectedでない場合、expectedの値をインスタンスの値に変更する。
この時の戻り値はfalse。
以下のような使い方となる。

atomic<int> val = 0;

int expected = val.load(); // C1
do {
  int next = expected + 1;
  // C2
} while( !val.compare_exchange_weak(expected, next) );

例えば、C1からC2までの間に別スレッドにより、valの値が100に変化したとする。
すると、条件式が成り立たないので、(A2)が実行され、valの最新の値である100がexpectedに入るので、 expectedが100になり、戻り値はfalseになる。
ここで、再度nextの値が計算され直されて101になり次の比較では、条件式が成立し、(A1)が実行され、valに102が設定され、戻り値がtrueなので、whileループから抜ける。
これがatomicに値の変更を行うための基本的な仕組みである。
なお、nextの値がexpectedの値に依存しない場合はdo文は不要で、while分だけあれば良い。