bool compare_exchange_strong(T& expected,
T desired,
memory_order success,
memory_order failure
) volatile noexcept; // (1) C++11
bool compare_exchange_strong(T& expected,
T desired,
memory_order success,
memory_order failure
) noexcept; // (2) C++11
bool compare_exchange_strong(T& expected,
T desired,
memory_order order = memory_order_seq_cst
) volatile noexcept; // (3) C++11
bool compare_exchange_strong(T& expected,
T desired,
memory_order order = memory_order_seq_cst
) noexcept; // (4) C++11
概要
強い比較で値を入れ替える。
- (1), (2) : 現在の値と
expected
が等値である場合に、success
メモリオーダーで現在の値をdesired
で置き換え、そうでなければfailure
メモリオーダーでexpected
を現在の値で置き換える - (3), (4) : 現在の値と
expected
が等値である場合に、現在の値をdesired
で置き換え、そうでなければexpected
を現在の値で置き換える。どちらの値置き換えの場合でもorder
メモリオーダーが使用される
テンプレートパラメータ制約
- (1) :
- C++20 :
atomic<T>::is_always_lock_free
がtrue
であること
- C++20 :
事前条件
failure
がmemory_order_release
,memory_order_acq_rel
ではないこと
効果
現在の値とexpected
をバイトレベルで等値比較を行い、true
である場合は現在の値をdesired
で置き換え、false
である場合はexpected
を現在の値で置き換える。
- (1), (2) : バイト等値比較が
true
の場合はsuccess
メモリオーダー、false
の場合はfailure
メモリオーダーに従って、アトミックに値の置き換えが行われる - (3), (4) : アトミックな値置き換えでは
order
メモリオーダーが使用される
戻り値
この関数を呼び出す前の*this
が保持する値とexpected
の等値比較の結果が返される。等値であればtrue
、そうでなければfalse
が返る。
例外
投げない
備考
この関数は、値が交換可能な場合はCAS (compare-and-swap) 操作が常に成功する。
compare_exchange_weak()
はより弱い命令であり、交換可能な場合でもCAS操作が失敗する可能性がある。
通常、CAS操作は、CASが成功するまでループさせる。
しかし、もしCAS操作でSpurious Failureが発生しなければループさせる必要が無くなるといった状況であれば、compare_exchange_strong()
を使うことで効率良くCASを行うことができる。
逆に言えば、そのような状況でないなら常にループでcompare_exchange_weak()
を利用すれば良い。
例
基本的な使い方
#include <iostream>
#include <atomic>
int main()
{
{
std::atomic<int> x(3);
// x == expectedなので、xは2に置き換えられる
int expected = 3;
bool result = x.compare_exchange_strong(expected, 2);
std::cout << std::boolalpha << result << " " << x.load() << " " << expected << std::endl;
}
{
std::atomic<int> x(3);
// x != expectedなので、expectedがxの値で置き換えられる
int expected = 1;
bool result = x.compare_exchange_strong(expected, 2);
std::cout << std::boolalpha << result << " " << x.load() << " " << expected << std::endl;
}
}
xxxxxxxxxx
#include <iostream>
#include <atomic>
int main()
{
{
std::atomic<int> x(3);
// x == expectedなので、xは2に置き換えられる
int expected = 3;
bool result = x.compare_exchange_strong(expected, 2);
std::cout << std::boolalpha << result << " " << x.load() << " " << expected << std::endl;
}
{
std::atomic<int> x(3);
// x != expectedなので、expectedがxの値で置き換えられる
int expected = 1;
bool result = x.compare_exchange_strong(expected, 2);
std::cout << std::boolalpha << result << " " << x.load() << " " << expected << std::endl;
}
}
出力
true 2 3
false 3 3
フラグのオン・オフをする例
#include <iostream>
#include <atomic>
#include <thread>
class my_atomic_flag {
std::atomic<bool> value_{false};
public:
void set() {
// 値がfalseだったらtrueにする。
// falseでなかったら (true) 、そのまま
bool expected = false;
value_.compare_exchange_strong(expected, true);
}
bool load() const {
return value_.load();
}
};
int main()
{
my_atomic_flag x;
// いずれかのスレッドの処理がおわったら (成功したら) フラグをオンにする
std::thread t1 {[&x] {
x.set();
}};
std::thread t2 {[&x] {
x.set();
}};
t1.join();
t2.join();
std::cout << std::boolalpha << x.load() << std::endl;
}
xxxxxxxxxx
#include <iostream>
#include <atomic>
#include <thread>
class my_atomic_flag {
std::atomic<bool> value_{false};
public:
void set() {
// 値がfalseだったらtrueにする。
// falseでなかったら (true) 、そのまま
bool expected = false;
value_.compare_exchange_strong(expected, true);
}
bool load() const {
return value_.load();
}
};
int main()
{
my_atomic_flag x;
// いずれかのスレッドの処理がおわったら (成功したら) フラグをオンにする
std::thread t1 {[&x] {
x.set();
}};
std::thread t2 {[&x] {
x.set();
}};
t1.join();
t2.join();
std::cout << std::boolalpha << x.load() << std::endl;
}
出力
true
バージョン
言語
- C++11
処理系
- Clang: 3.2 ✅
- GCC: 4.7.0 ✅
- Visual C++: 2012 ✅, 2013 ✅
関連項目
参照
- atomic compare_exchange_weak/strong関数 - yohhoyの日記
- N2748 Strong Compare and Exchange
- cbloom rants: 07-14-11 - compare_exchange_strong vs compare_exchange_weak
- What does 'spurious failure' on a CAS mean? - StackOverflow
- “Strong” and “weak” hardware memory models - Sutter’s Mill
- Understand
std::atomic::compare_exchange_weak()
in C++11 - Eric Z's blog - P1831R1 Deprecating
volatile
: library- C++20での、
volatile
版への制約追加
- C++20での、