memory_order_seq_cst 和 memory_order_release 的可能排序 使这种情况发生的重新排序

如何解决memory_order_seq_cst 和 memory_order_release 的可能排序 使这种情况发生的重新排序

参考以下代码

auto x = std::atomic<std::uint64_t>{0};
auto y = std::atomic<std::uint64_t>{0};

// thread 1
x.store(1,std::memory_order_release);
auto one = y.load(std::memory_order_seq_cst);

// thread 2
y.fetch_add(1,std::memory_order_seq_cst);
auto two = x.load(std::memory_order_seq_cst);

这里有没有可能,onetwo 都是 0?


(我似乎遇到了一个可以解释的错误,如果 onetwo 在上面的代码运行后都可以保持 0 的值。而且排序规则对我来说太复杂了找出上面可能的排序。)

解决方法

是的,两种负载都有可能获得 0

在线程 1 中,y.load 可以“通过”x.store(mo_release),因为它们不是 seq_cst。 ISO C++ 保证必须存在的 seq_cst 操作的全局总顺序 only 包括 seq_cst 操作。

(就普通 CPU 的硬件/cpu 架构而言,负载可以在 release-store 离开存储缓冲区之前从相干缓存中获取一个值。在这种情况下,我发现从我怎么知道它为 x86(或 to generic release and acquire operations)编译,然后应用 asm 内存排序规则。应用这个推理假设正常的 C++->asm mappings 是安全的,并且总是至少与 C++ 内存一样强大模型。如果你能用这种方式找到合法的重新排序,你就不需要费力地通过 C++ 形式主义。但如果你不这样做,那当然不能证明它在 C++ 中是安全的抽象机器。)

无论如何,要意识到的关键点是 seq_cst 操作不像 atomic_thread_fence(mo_seq_cst) - 单个 seq_cst 操作只需以这种方式恢复/保持顺序一致性它们与其他 seq_cst 操作交互,而不是与普通的 Acquire/release/acq_rel 交互。 (同样,获取和释放栅栏是更强的双向屏障,不像获取和释放 操作Jeff Preshing explains。)


使这种情况发生的重新排序

这是唯一可能的重新排序;其他可能性只是两个线程的程序顺序的交错。让商店“发生”(变得可见)最后会导致 0,0 结果。

我将 onetwo 重命名为 r1r2(每个线程中的本地“寄存器”),以避免编写 one == 0 之类的内容。

// x=0 nominally executes in T1,but doesn't have to drain the store buffer before later loads
auto r1 = y.load(std::memory_order_seq_cst);   // T1b             r1 = 0 (y)
         y.fetch_add(1,std::memory_order_seq_cst);      // T2a   y = 1 becomes globally visible
         auto r2 = x.load(std::memory_order_seq_cst);    // T2b   r2 = 0 (x)
x.store(1,std::memory_order_release);         // T1a             x = 0 eventually becomes globally visible

这可能在 x86 上实际发生,但有趣的是在 AArch64 上不会。 x86 可以在没有额外障碍的情况下进行发布存储(只是一个普通的存储),并且 seq_cst 加载的编译与普通获取相同,只是一个普通的加载。

在 AArch64 上,release 和 seq_cst 存储使用 STLR。 seq_cst 加载使用 LDAR,它与 STLR 有特殊的交互,在最后一个 STLR 从存储缓冲区中排出之前不允许读取缓存。因此,ARMv8 上的 release-store / seq_cst 加载与 seq_cst store / seq_cst 加载相同。 (ARMv8.3 添加了 LDAPR,通过让获取加载以不同的方式编译来允许真正的获取/释放;请参阅 this Q&A。)

但是,它也可能发生在许多使用单独屏障指令的 ISA 上,例如 ARM32:发布存储通常使用屏障完成,然后是普通存储,防止使用较早加载重新排序/存储,但不会停止重新排序。如果 seq_cst 加载避免在自身之前需要一个完整的屏障(这是正常情况),那么存储可以在加载后重新排序。

例如,ARMv7 上的发布存储是 dmb ish; str,而 seq_cst 加载是 ldr; dmb ish,因此您有 str / ldr,它们之间没有障碍。

在 PowerPC 上,由于 seq_cst 负载是 hwsync; ld; cmp; bc; isync,所以在负载之前有一个完整的屏障。 (HeavWeight Sync 是我认为防止 IRIW 重新排序的一部分,以阻止同一物理核心上的 SMT 线程之间的存储转发,只有在其他核心实际上变得全局可见时才能看到它们。)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res