C++的memory order怎么理解
发表于:2025-01-30 作者:千家信息网编辑
千家信息网最后更新 2025年01月30日,这篇文章主要讲解了"C++的memory order怎么理解",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"C++的memory order怎么理解"吧
千家信息网最后更新 2025年01月30日C++的memory order怎么理解
这篇文章主要讲解了"C++的memory order怎么理解",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"C++的memory order怎么理解"吧!
Key Points:
要从"防止编译器重排"与"防止CPU乱序"两个角度去理解 memory_order release semantics 一言以蔽之,一般表示 "最后 Store" acquire semantics 一言以蔽之,一般表示 "最先 Load" 注意 x86_64 CPU 一般^1都满足 strong memory model 特性:CPU 四种可能发生的乱序中,只允许StoreLoad乱序(或称为StoreLoad重排)
1)与 atomic 连用
memory_order_relaxed:atomic variable 的 relaxed 操作和普通变量普通操作有何区别?
普通变量的SL操作并不保证原子性,而 atomic 变量的所有操作都是保证原子性的。(TODO: 甚至不会被中断打断?) x86_64 实测:atomic 变量结合任意 memory_order 都能有效防止编译器重排。
memory_order_consume:所有后续 data-dependent 的 S/L 操作禁止被 re-order 到本 L 前面。和 release-S 连用。
memory_order_acquire:所有后续 S/L 操作禁止被 re-order 到本 L 前面。和 release-S 连用。
acquire 操作强调本 L 一定是"最先 Load"。
x86_64 实测:
a.load(acquire/relaxed) 产生的机器码相同。猜测是由于 x86_64 的 strong-memory-model 性质,禁止 L-S 和 L-L 重排,其任何 Load 都具有 acquire 语义。 UB 操作:a.store(acquire),则机器码会在 S 后面添加一个 mfence。此时实际产生的语义为:所有后续 S/L 操作禁止被 re-order 到本 S 前面。猜测是由于 x86_64 CPU 允许 S-L re-order,那么要保证此 S 后面的 S/L 不被重排到本 S 前,那么只能加入 fence 指令。 UB 操作:a.load(release) 产生的机器码等同于 a.load(acquire)。(注意并不符合类似 S-release 的语义 "所有前面 S/L 操作禁止被 re-order 到本 L 后面,如果要符合的话必须在本 L 前面加 mfence)" UB 操作:a.load() 接所有 memory_order 都等效于 a.load(acquire),即编译产生同样的机器码。
memory_order_release:所有前面 S/L 操作禁止被 re-order 到本 S 后面。和 acquire/consume-L 连用。
release 操作强调本 S 操作一定是"最后 Store"。
x86_64 实测:
a.store(release/relaxed) 产生的机器码相同。猜测是由于 x86_64 的 strong-memory-model 性质,禁止 S- S 和 L- S 重排,其任何 Store 都具有 release 语义。 UB 操作:a.store(acquire/consume/acq_rel/seq_cst) 产生的机器码相同,都是在本 S 后面加入一个 mfence
指令。猜测是由于 x86_64 中,只需要在 S 后面加一个 mfence,该 S 就能同时满足"本 S 前所有的 S/L 禁止被重排到本 S 之后(即 release 语义)"与"本 S 后所有的 S/L 禁止被重排到本 S 之前(类似 L-acquire 语义)"的两个条件
memory_order_acq_rel:适用于RMW操作。
1)本线程所有 S/L 操作(无论前后)禁止被 re-order 到本 S 前或后。 为什的只提到S?(TODO: 这个RMW操作一定是保证原子性的吗?) 其实是只需要关心 S 即可。因为RMW操作的特性类似一个 LS 操作,这里 S 已经作为了同步点,本线程 L 前的 S/L 即使重排也只能重排在本 L 后且本 S 前,即使发生这种重排也是没有关系的。而本 S 后所有的 S/L 都不可被重排到本 S 前,这样就间接保证了不可被重排到本 L 前,从而也保证了 acquire 语义。 2)执行了相应 release 操作的其他线程,其 release 前的所有 S 一定发生在本 S 前。 这句话其实暗含了其他线程造成的该原子变量本身的 S 一定是发生在本 L 前的。因为如果其他线程对该原子变量的改动还没有被本线程观察到的话,可以认为其他线程并没有写它,也就不存在同步问题。既然观察到了变化,那么这个变化伴随的更改顺序关系才需要被讨论。 由于 S 比 L 慢,因此这个语义只要求其他线程被 release 的 S 一定是发生在本 S 之前就可以,没必要严格到必须发生在本 L 之前,那样效率会变低。不过这个要求已经比单纯的 acquire 严格了,即要求其他线程被 release 的 S 可以发生在本 L 后但必须发生在本 S 前,而单纯的 acquire 只暗含本 L 之后,就能看到相关线程所有被 release 的 S 了 术语情景:x=1; y.store(1, release); 此时称为 x=1 和 y=1 这些 S 最后执行了 release 操作。或者说 x=1 和 y=1 都是被该线程 release 的 S 操作,且同步点是 Y。
memory_order_seq_cst:
对于 L 执行 acquire 语义 对于 S 执行 release 语义 对于 RMW 执行 acq_rel 语义,并且对所有线程执行了 seq_cst 操作的 S,都存在一个 TSO TSO:Total Single Order,所有线程观察到的 S 顺序都是一样的? x86_64 实测: seq_cst 与 load 操作连用时,与所有 memory_order 都等效。即编译产生同样的机器码。 seq_cst 与 store 操作连用时,与 acquire/consume/acq_rel 等效。
感谢各位的阅读,以上就是"C++的memory order怎么理解"的内容了,经过本文的学习后,相信大家对C++的memory order怎么理解这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!
线程
语义
机器
机器码
变量
保证
原子
C++
实测
猜测
编译
普通
相同
同步
学习
观察
一言以蔽之
两个
内容
性质
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
华为服务器管理口网关
网络技术应用图标图片
易通网络安全ppt
如何注注销数据库账号
网络安全团队发展方向
大数据时代网络安全培训机构
大学生校园安全和网络安全
药品广告数据库是江苏10秒
网络安全监管办法
国家网络安全周作品
tbc不排队人多的服务器
现任公安部网络安全局局长
软件开发外包前十
log4j 数据库配置
计算机网络技术算法程序
数据库建表实验心得体会
进行软件开发的专业
静安区信息化网络技术怎么样
服务器怎么配公网地址
江苏数据库安全箱批量定制
git跟踪数据库开发
数据库谓词是什么
网络安全法开始行驶的时间是
软件开发文档标识
交行 软件开发中心 知乎
access做数据库
表不是数据库对象
学校护苗网络安全课小结
网络安全宣传观后感电子版
数据库跟c语言哪个好学