- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我对以下代码中的操作顺序有疑问:
std::atomic<int> x;
std::atomic<int> y;
int r1;
int r2;
void thread1() {
y.exchange(1, std::memory_order_acq_rel);
r1 = x.load(std::memory_order_relaxed);
}
void thread2() {
x.exchange(1, std::memory_order_acq_rel);
r2 = y.load(std::memory_order_relaxed);
}
鉴于 cppreference 页面 (https://en.cppreference.com/w/cpp/atomic/memory_order) 上对 std::memory_order_acquire
的描述,
A load operation with this memory order performs the acquire operation on the affected memory location: no reads or writes in the current thread can be reordered before this load.
似乎很明显,在同时运行 thread1
和 thread2
之后永远不会有 r1 == 0 && r2 == 0
的结果.
但是,我在 C++ 标准中找不到任何措辞(目前正在查看 C++14 草案),该标准确保两个宽松的加载不能通过获取-发布交换重新排序。我错过了什么?
编辑:正如评论中所建议的,实际上可以使 r1 和 r2 都等于 0。我已将程序更新为使用 load-acquire,如下所示:
std::atomic<int> x;
std::atomic<int> y;
int r1;
int r2;
void thread1() {
y.exchange(1, std::memory_order_acq_rel);
r1 = x.load(std::memory_order_acquire);
}
void thread2() {
x.exchange(1, std::memory_order_acq_rel);
r2 = y.load(std::memory_order_acquire);
}
现在可以同时执行 thread1
和 thread2
和 r1
和 r2
都等于 0 >?如果不是,哪些 C++ 规则可以防止这种情况发生?
最佳答案
该标准没有根据操作如何围绕具有特定排序参数的原子操作进行排序来定义 C++ 内存模型。相反,对于获取/释放排序模型,它定义了诸如“同步”和“发生前”之类的正式关系,用于指定数据如何在线程之间同步。
N4762,§29.4.2 - [atomics.order]
An atomic operation A that performs a release operation on an atomic object M synchronizes with an atomic operation B that performs an acquire operation on M and takes its value from any side effect in the release sequence headed by A.
在第 6.8.2.1-9 节中,该标准还规定,如果存储 A 与加载 B 同步,则任何在 A 之前排序的线程间“发生之前”任何在 B 之后排序的内容。
在您的第二个示例(第一个甚至更弱)中没有建立“同步与”(因此线程间发生之前)关系,因为缺少运行时关系(检查负载的返回值)。
但即使您确实检查了返回值,它也无济于事,因为 exchange
操作实际上并没有“释放”任何东西(即在这些操作之前没有对内存操作进行排序)。原子加载操作不会“获取”任何内容,因为加载后没有任何操作被排序。
因此,根据标准,两个示例中载荷的四种可能结果(包括 0 0)中的每一种都是有效的。事实上,标准给出的保证在所有操作上都不比memory_order_relaxed
强。
如果要在代码中排除 0 0 结果,则所有 4 个操作都必须使用 std::memory_order_seq_cst
。这保证了所涉及操作的单一总顺序。
关于c++ - C++ 内存模型中的哪些确切规则可以防止在获取操作之前重新排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52606524/
通过多次搜索和pytorch文档本身,我可以发现在嵌入层内部有一个查找表,用于存储嵌入向量。我无法理解的是: 在这一层的培训期间究竟发生了什么? 权重是多少,以及这些权重的梯度是如何计算的? 我的直觉
当应用程序有大量数据(400M)要写入非阻塞套接字时,write() 返回EWOULDBLOCK 或EAGAIN 当发送缓冲区变满时。 当套接字被(e)轮询时,我有时会看到发送缓冲区中有 7M 空间(
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我经常阅读一些编程语言对模块的支持(“一流”)(OCaml,Scala,TypeScript [?]),并且最近偶然发现了这样的答案,即在Scala的显着特征中引用模块作为一流公民。 我以为我很清楚模
我已经提交了一个自定义的开放图表故事,但它被拒绝并显示以下消息: 打开图表捐赠(行动类型)提交内容、操作、对象和使用说明必须以英文提交。您可以在应用程序面板的“本地化”选项卡中翻译操作和对象。 如果我
给定一个任意的 boolean 值列表,确定其中一个恰好为真的最优雅的方法是什么? 最明显的 hack 是类型转换:将 false 转换为 0,将 true 转换为 1,然后对它们求和,并返回 sum
这个问题在这里已经有了答案: When to use extern "C" in simple words? [duplicate] (7 个答案) 关闭 9 年前。 如果您想将此问题标记为重复问题
我是一名优秀的程序员,十分优秀!