5.2.3 std::atomic的相关操作

5.2.3 std::atomic的相关操作

最基本的原子整型类型就是 std::atomic<bool> 。如你所料,它有着比 std::atomic_flag更加齐全的布尔标志特性。虽然它依旧不能拷贝构造和拷贝赋值,但是你可以使用一个非原子的bool类型构造它,所以它可以被初始化为true或false,并且你也可以从一个非原子bool变量赋值给 std::atomic<bool> 的实例:

std::atomic<bool> b(true);
b = false;

另一件需要注意的事情是,非原子bool类型的赋值操作不同于通常的操作(转换成对应类型的引用,再赋给对应的对象):它返回一个bool值来代替指定对象。这是在原子类型中,另一种常见的模式:赋值操作通过返回值(返回相关的非原子类型)完成,而非返回引用。如果一个原子变量的引用被返回了,任何依赖与这个赋值结果的代码都需要显式加载这个值,潜在的问题是,结果可能会被另外的线程所修改。通过使用返回非原子值进行赋值的方式,你可以避免这些多余的加载过程,并且得到的值就是实际存储的值

虽然有内存顺序语义指定,但是使用store()去写入(true或false)还是好于 std::atomic_flag 中限制性很强的clear()。同样的,test_and_set()函数也可以被更加通用的exchange()成员函数所替换,exchange()成员函数允许你使用你新选的值替换已存储的值,并且自动的检索原始值。 std::atomic<bool>也支持对值的普通(不可修改)查找,其会将对象隐式的转换为一个普通的bool值,或显式得调用load()来完成。如你预期,store()是一个存储操作,而load()是一个加载操作。exchange()是一个“读-改-写”操作:

std::atomic<bool> b;
bool x = b.load(std::memory_order_acquire);
b.store(true);
x = b.exchange(false, std::memory_order_acq_rel);

 

std::atomic<bool>提供的exchange(),不仅仅是一个“读-改-写”的操作;它还介绍了一种新的储方式:和当前值与预期值一致时,存储新值的操作。

存储一个新值(或旧值)取决于当前值,这是一种新型操作,叫做“比较/交换”,它的形式表现为compare_exchange_weak()compare_exchange_strong()成员函数。比较/交换”操作是原子类型编程的基石;它比较原子变量的当前值和提供的预期值,当两值相等时,存储预期值。当两值不等,预期值就会被更新为原子变量中的值。“比较/交换”函数值是一个bool变量,当返回true时执行存储操作,当 false则更新期望值。

对于compare_exchange_weak()函数,当原始值与预期值一致时,存储也可能会不成功;在这个例子中变量的值不会发生改变,并且compare_exchange_weak()的返回是false。这可能发生在缺少独立“比较-交换”指令的机器上,当处理器不能保证这个操作能够自动的完成—— 可能是因为线程的操作将指令队列从中间关闭,并且另一个线程安排的指令将会被操作系统所替换(这里线程数多于处理器数量)。这被称为“伪失败”(spurious failure),因为造成这种情况的原因是时间,而不是变量值。

因为compare_exchange_weak()可以“伪失败”,所以这里通常使用一个循环:

bool expected = false;
extern atomic<bool> b; // 设置些什么
while(!b.compare_exchange_weak(expected, true) && !expected);

在这个例子中,循环中expected的值始终是false,表示compare_exchange_weak()会莫名的失败。

另一方面,如果实际值与期望值不符,compare_exchange_strong()就能保证值返回false。这就能消除对循环的需要,就可以知道是否成功的改变了一个变量,或已让另一个线程完成。

如果你想要改变变量值,且无论初始值是什么(可能是根据当前值更新了的值),更新后的期望值将会变更有用;经历每次循环的时候,期望值都会重新加载,所以当没有其他线程同时修改期望时,循环中对compare_exchange_weak()或compare_exchange_strong()的调用都会在下一次(第二次)成功。如果值的计算很容易存储,那么使用compare_exchange_weak()能更好的避免一个双重循环的执行,即使compare_exchange_weak()可能会“伪失败”(因此 compare_exchange_strong()包含一个循环)。另一方面,如果值计算的存储本身是耗时的,那么当期望值不变时,使用compare_exchange_strong()可以避免对值的重复计算。对于 std::atomic<bool> 这些都不重要——毕竟只可能有两种值——但是对于其他的原子类型就有较大的影响了。

“比较/交换”函数很少对两个拥有内存顺序的参数进行操作,这就允许内存顺序语义在成功和失败的例子中有所不同;其可能是对memory_order_acq_rel语义的一次成功调用,而对 memory_order_relaxed语义的一次失败的调动。一次失败的“比较/交换”将不会进行存储,所以“比较/交换”操作不能拥有memeory_order_release或memory_order_acq_rel语义。因此, 这里不保证提供的这些值能作为失败的顺序。你也不能提供严格的失败内存顺序;当你需要 memory_order_acquire或memory_order_seq_cst作为失败语序,你必须要像“指定它们是成 功语序”时那样做。

如果你没有指定失败的语序,那就假设和成功的顺序是一样的,除了release部分的顺序: memory_order_release变成memory_order_relaxed,并且memoyr_order_acq_rel变成 memory_order_acquire。如果你都不指定,他们默认顺序将为memory_order_seq_cst,这个 顺序提供了对成功和失败的全排序。下面对compare_exchange_weak()的两次调用等价于:

std::atomic<bool> b;
bool expected;
b.compare_exchange_weak(expected, true, memory_order_acq_rel, memory_order_acquire);
b.compare_exchange_weak(expected, true, memory_order_acq_rel);

 

在5.3节中会详解对于不同内存顺序选择的结果。

std::atomic<bool> 和 std::atomic_flag 的不同之处在于, std::atomic<bool> 不是无锁的; 为了保证操作的原子性,其实现中需要一个内置的互斥量。当处于特殊情况时,你可以使用is_lock_free()成员函数,去检查  std::atomic<bool> 上的操作是否无锁。这是另一个,除了std::atomic_flag 之外,所有原子类型都拥有的特征。

第二简单的原子类型就是特化原子指针—— std::atomic<T*> ,接下来就看看它是如何工作的吧。

 
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
std::atomic::load是一个成员函数,用于获取std::atomic对象的当前值。它接受一个可选的std::memory_order参数来指定内存访问顺序,默认值为std::memory_order_seq_cst,即顺序一致的内存顺序。 该函数返回一个T类型的值,表示std::atomic对象的当前值。这个操作是原子的,意味着在多线程环境中,其他线程不能同时修改或访问该std::atomic对象的值。 注意,std::atomic::load本身是线程安全的,并不需要额外的同步机制来保证原子性。它可以在多个线程之间安全地读取std::atomic对象的值。 引用:std::atomic<T>::load定义 T load( std::memory_order order = std::memory_order_seq_cst ) const noexcept; 。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [c++11:std::atomic](https://blog.csdn.net/weixin_40179091/article/details/109318237)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [5.2.3 std::atomic相关操作](https://blog.csdn.net/baidu_20351223/article/details/116019312)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值