atomic_flag atomic_flag 一种简单的原子布尔类型,只支持两种操作,test-and-set 和 clear
1. test表示先测试(读取当前atomic_flag的值)并返回个这结果值;
2. set表示将atomic_flag状态设置为ture。
3. 初始状态c++20之前不确定 ,c++20之后是false
4.ATOMIC_FLAG_INIT: 如果某个 std::atomic_flag 对象使用该宏初始化,那么可以保证该 std::atomic_flag 对象在创建时处于 clear 状态。
std::atomic_flag lock_stream = ATOMIC_FLAG_INIT;
5.test_and_set() 函数检查 std::atomic_flag 标志,如果 std::atomic_flag 之前没有被设置过,则设置 std::atomic_flag 的标志,并返回先前该 std::atomic_flag 对象是否被设置过(true or false ,有可能原本就是true如果之前 std::atomic_flag 对象已被设置,则返回 true,否则返回 false。)
m_isNotStop.test_and_set();
6.std::atomic_flag::clear() 清除 std::atomic_flag 标志使得下一次调用 std::atomic_flag::test_and_set 返回 false。
7. c++20以前只提供了上面两个方法
8. is_lock_free 返回true 支持无锁
总得来说,有下面五个通用方法
store // 原子写操作
load // 对应的原子读操作。
exchange // 允许2个数值进行交换,并保证整个过程是原子的。
compare_exchange_weak //
compare_exchange_strong //
// 而compare_exchange_weak和compare_exchange_strong则是著名的CAS(compare and set)。参数会要求在这里传入期待的数值和新的数值。它们对比变量的值和期待的值是否一致,如果是,则替换为用户指定的一个新的数值 返回true。如果不是,那么期待值(expected)将被更新为原子变量的当前值。 返回false
/*
compare_exchange_strong:atomic库中的一个函数,入参是3个,expect,desire,memoryorder,意思是如果当前的变
量this的值==expect值,则将this值改为desire,并返回true,否则,返回false,不进行修改,即进行一个读的操作。通常用于例如线程B等待线程A执行完毕,或者执行到某个步骤。此时线程B可以进行while等待,线程A在执行到对应步骤,将对应的原子变量置为expect值即可。类似于“接力运动”。这里由于会进行读写操作,所以,memory order一般是acq rel,而A线程由于要保证都执行完毕,执行顺序没有关系,所以一般是Release的
weak版和strong版的区别:
weak版本的CAS允许偶然出乎意料的返回(比如在字段值和期待值一样的时候却返回了false),不过在一些循环算法中,这是可以接受的。通常它比起strong有更高的性能。
bool compare_exchange_weak(T& expected, T desired, std::memory_order success, std::memory_order failure);
参数:
expected (输入输出): 指向期望值的引用。如果比较失败,expected 会被原子更新为 *this 的当前值。
desired: 需要存储的新值。
success / failure: 分别指定交换成功和失败时的内存序约束,其中 failure 不能为 memory_order_release 或 memory_order_acq_rel。
返回值 (bool):
true:交换成功,*this 被原子更新为 desired。
false:交换失败(可能是真实值不符或伪失败),expected 被原子更新为 *this 的当前值
weak: 为了不同的cpu硬件架构性能, 即使值相等,也可能失败(允许伪失败), 必须配合循环使用
int expected = 0;
while (!atom.compare_exchange_weak(expected, 1)) {
expected = 0; // 必须重置
}
strong ,只要值相等,就一定成功, 适合只尝试一次的场景
int expected = 0;
if (atom.compare_exchange_strong(expected, 1)) {
// 成功
}
感觉大多数情况是为了weak ,而必须加循环,,而不是因为有循环而去使用weak?
1.weak ≈ “原样暴露 CPU 指令”
2. 从实现角度看,你的理解非常接近事实:
compare_exchange_weak是“真实的原子指令语义”
compare_exchange_strong是“给人类用的语义糖”
这也是为什么:
- 标准库实现
- lock-free 算法论文
- STL 内部实现
👉 几乎清一色用 weak + 循环
总结: weak 是为硬件存在的
strong 是为程序员存在的
循环不是目的,是代价, 性能优化:在循环中使用时,weak 版本通常比 strong 版本性能更高。
////////////////////////////////////////////////////////////////////////////////
为什么有两个内存序参数?
-
成功内存序参数 (
success):- 当
compare_exchange_weak成功时,需要保证新值对其他线程可见,这通常需要较强的内存序。例如,我们可能希望在交换成功后发布一个存储顺序(std::memory_order_release)或更强的顺序(如std::memory_order_acq_rel或std::memory_order_seq_cst)。
- 当
-
失败内存序参数 (
failure):- 当
compare_exchange_weak失败时,不需要发布新值,但仍需要保持某种内存顺序以确保读取预期值的正确性。通常这会是一个较弱的序列,例如std::memory_order_relaxed或std::memory_order_acquire。
- 当
#include <atomic>
int main(int argc, char ** argv)
{
std::atomic<int> counter(1);
int expected = 3;
bool success = counter.compare_exchange_weak(expected, 1);
if (success)
{
// 交换成功,counter现在是1,expected现在是1(因为它被更新了)
printf("true: %d %d\n", success, counter.load());
}
else
{
// 交换失败,counter的值不是0,expected现在是counter的当前值
printf("false: %d %d %d\n", success, counter.load(), expected);
}
}
atomic <T>
atomic_int
atomic<int> foo(0);
1. std::atomic<T>::store()是


1542

被折叠的 条评论
为什么被折叠?



