在使用堆栈本地对象和销毁对象之间的关系之前是否发生过什么?

如何解决在使用堆栈本地对象和销毁对象之间的关系之前是否发生过什么?

我观看了Herb Sutter的这个谈话:https://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2

围绕1:25的标记,他谈到了为什么共享指针的原子引用计数器的减量需要获得释放存储器的顺序。

视频中的逻辑如下:

  1. 有两个线程,都同时调用fetch_sub。
  2. 线程1在减量之前使用了该对象。它将参考计数器从2减少到1。
  3. 线程2从1-> 0开始递减,并删除控制块指针。

据说获取/释放的原因是,从线程2的角度来看,线程1中对象的使用可以在线程1中的递减以下重新排序。然后,线程2从1-> 0递减。并在A行发生之前删除该对象。

以下是幻灯片:

enter image description here

但是在共享指针实现中,析构函数(忽略副本分配和手动释放)在减量之前不使用该对象。这意味着在销毁共享指针之后,必须重新排序对共享指针对象的函数调用。

这让我很困惑。这是我的具体问题:

  1. 真的可以在使用对象之前对析构函数进行重新排序吗?假设您有一个唯一的指针而不是一个共享的指针。如果唯一ptr的析构函数在使用前已重新排序,则您将访问已删除的内存。那不对。

  2. 从线程2的角度来看,幻灯片中线程1中的线A是否出现在线程1的减量下方,这有什么关系?假设线程1中的行A出现在减量的上方,那么一旦将缓存行推送到处理器2中,线程2的对象状态就不会被更新,并且函数调用的任何副作用对线程2来说是显而易见的吗?该代码仅在一个线程上运行。幻灯片上的相关行是:“对于线程2,线A似乎移动到线程1的减量以下”。

解决方法

赫伯·萨特(Herb Sutter)绝对知道他的东西,但是如果有人争论可能的“重新排序”,我通常会不喜欢它,因为这样的论点通常没有提供为什么实际上可能进行重新排序的全部细节。 C ++标准对指令是否或何时可以重新排序没有任何说明。它仅定义了“先发生”关系,并且可能应用的任何重新排序最终都是由于应用了先发生后关系规则(当然还有无处不在的“假设”规则)的结果。

为什么这么重要?因为事前发生关系也是定义数据竞争的基础:

如果两个表达式求值之一修改了一个内存位置(4.4),而另一个表达式读取或修改了同一个内存位置,则冲突。 [..]

如果程序的执行包含两个潜在的并发冲突操作,其中至少一个不是原子操作,并且都没有先于另一个[..]

,则执行该程序将导致数据争用。 >

众所周知,数据竞争会导致UB,因此,任何有关使用原子的多线程代码正确性的争论都必须基于事前发生。也就是说,在需要建立关系之前会发生什么,以及如何建立关系。


所以让我们看一下示例:

Thread 1:
... // use object
if (control_block_ptr->refs.fetch_sub(1,std::memory_order_release) == 1) {
  // branch not taken
}

Thread 2:
if (control_block_ptr->refs.fetch_sub(1,std::memory_order_release) == 1) {
  delete control_block_ptr;
}

您在这里的要求是delete必须在使用后发生

假设对象包含一个std::string,线程1为该字符串分配一个值,即我们有一个 write操作。当线程2删除对象时,我们还需要删除字符串成员,这显然涉及至少 read操作。这是冲突操作的教科书示例,因此我们必须确保线程1中的分配在发生之前发生,否则我们将进行数据争夺!仅使用memory_order_release,fetch_sub操作就无法与任何内容同步(释放操作本身实际上是没有意义的),因此不存在任何before-before关系。

我们如何解决?通过确保refs上的操作彼此同步。如果我们使用memory_order_acq_rel,则线程2中的fetch_sub与线程1中的fetch_sub同步,从而建立事前发生关系。 “使用对象”在线程1中的fetch_sub之前排序,在线程2中的fetch_subdelete之前排序。因此,我们有:

  • t1.use -sb-> t1.fetch_sub -sw-> t2.fetch_sub -sb-> t2.delete

其中-sb->表示“先后顺序”,-sw->表示“同步”。而且因为发生在之前是可传递的,所以这意味着t1.use发生在t2.delete之前。

另一种解决方案是在refs.load(memory_order_acquire)之前添加一个额外的delete,然后我们可以继续使用memory_order_release作为fetch_sub,因为t2.load与t1.fetch_sub同步。

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

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 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 -> 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("/hires") 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<String
使用vite构建项目报错 C:\Users\ychen\work>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)> insert overwrite table dwd_trade_cart_add_inc > select data.id, > data.user_id, > data.course_id, > date_format(
错误1 hive (edu)> insert into huanhuan values(1,'haoge'); 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> 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 # 添加如下 <configuration> <property> <name>yarn.nodemanager.res