c - 了解发布顺序并与 C11 同步
问题描述
我试图理解内存模型和读取,并且对定义如下5.1.2.4 Multi-threaded executions and data races
的释放序列概念感到困惑:5.1.2.4(p10)
A
以原子对象上 的释放操作为首的释放序列M
是 的修改顺序中副作用的最大连续子序列M
,其中第一个操作是A
,并且每个后续操作要么由执行释放的同一线程执行,要么是原子读-修改-写操作。
随后用于定义与 at 同步,5.1.2.4(p11)
如下所示:
某些库调用与另一个线程执行的其他库调用同步。特别是,
A
对对象执行释放操作的原子操作与对以 为首的释放序列中的任何副作用执行获取操作并读取由任何副作用写入的值M
的原子操作同步。B
M
A
我可以想象下面的例子:
#include <stdatomic.h>
Atomic_ int a; // <<--- M
int main(void){
atomic_store_explicit(&a, 42, memory_order_release); // <<--- A
atomic_store_explicit(&a, 442, memory_order_release);
atomic_store_explicit(&a, 242, memory_order_release);
int a_value = atomic_load_explicit(&a, memory_order_acquire);
atomic_store_explicit(&a, 242, memory_order_release);
}
我目前将其理解为A
存在atomic_store_explicit(&a, 42, memory_order_release);
,其发布顺序是
atomic_store_explicit(&a, 442, memory_order_release);
atomic_store_explicit(&a, 242, memory_order_release);
但atomic_store_explicit(&a, 242, memory_order_release);
不包括在内,因为它后面int a_value = atomic_load_explicit(&a, memory_order_acquire);
是一个获取操作。
现在synchronize with
来看对对象 M 执行释放操作的原子操作 A 与对 M 执行获取操作并读取由 A 为首的释放序列中的任何副作用写入的值的原子操作 B 同步。意味着A 的释放序列中的所有释放操作都可以通过获取操作可见,该操作是atomic_load_explicit(&a, memory_order_acquire);
是正确的还是我错过了什么?
解决方案
不,该序列包括所有四个存储操作,因为中间加载操作是由同一个线程完成的。基本上,对于您的示例,您不必参考同步。由于游戏中只有一个线程,“sequenced before”已经为您提供了您想要的所有信息。优化器甚至可以省略除简化示例中的最后一个之外的所有存储,即使对于原子操作也是如此。(好吧,volatile
在 的规范中有atomic_store
,但我们暂时忘记这一点。)
我认为,释放序列概念的想法是识别不同线程的读取可能截取存储值的点,并在序列中的第一个存储操作之后使读取依赖排序。为此,可以忽略线程读取它已写入的值的事实。
推荐阅读
- html - 与网页交互以使用 R 下载数据
- javascript - 当我尝试实现接口时,为什么 flowtype 会抱怨?
- javascript - 如何将字符串拆分为用 [ ] 括起来的多个子字符串,并且在子字符串中还可以找到分隔符?
- c++ - 如何删除静态对象
- oauth - 尝试在 GCE 上为 chrome-remote-desktop 启动主机时出现 OAuth 错误
- awk - 搜索和替换字符串,但保留一些字符
- java - 为什么 binarysearch 方法将负返回值减少 1
- node.js - 在 Linux VPS Apache Server 上部署 Angular Universal(ng-toolkit/universal)
- java - 在 Android Studio 中实现回收视图时应用程序崩溃
- c++ - 为什么我不能定义一元运算符,然后在 MSVC 的模板类中声明一个具有相同名称的朋友二元运算符?