std :: memory_order和指令顺序,澄清 [英] std::memory_order and instruction order, clarification

查看:149
本文介绍了std :: memory_order和指令顺序,澄清的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我想确切地说明指令排序的含义,以及它如何受到std::memory_order_acquirestd::memory_order_release等的影响...

I want to figure exactly the meaning of instruction ordering, and how it is affected by the std::memory_order_acquire, std::memory_order_release etc...

在我链接的问题中,已经提供了一些细节,但是我觉得所提供的答案不是真正关于订单的(这是我想要的更多),而是有点动机,为什么这样做是必需的,等等.

In the question I linked there's some detail already provided, but I felt like the provided answer isn't really about the order (which was more what was I looking for) but rather motivating a bit why this is necessary etc.

我将引用相同的示例作为参考

I'll quote the same example which I'll use as reference

#include <thread>
#include <atomic>
#include <cassert>
#include <string>

std::atomic<std::string*> ptr;
int data;

void producer()
{
    std::string* p  = new std::string("Hello");
    data = 42;
    ptr.store(p, std::memory_order_release);
}

void consumer()
{
    std::string* p2;
    while (!(p2 = ptr.load(std::memory_order_acquire)))
        ;
    assert(*p2 == "Hello"); // never fires
    assert(data == 42); // never fires
}

int main()
{
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join(); t2.join();
}

简而言之,我想弄清楚两行指令顺序到底发生了什么

In a nutshell I want to figure what exactly happens with the instruction order at both line

ptr.store(p, std::memory_order_release);

while (!(p2 = ptr.load(std::memory_order_acquire)))

根据文档优先关注

...在此存储之后,当前线程中的任何读取或写入操作都无法重新排序...

... no reads or writes in the current thread can be reordered after this store ...

我一直在观看很少的讲座来了解此订购问题,我了解为什么它现在很重要.我还不太清楚编译器如何翻译订单说明,我认为文档给出的示例也不是特别有用,因为在运行producer的线程中执行存储操作之后,没有其他指令,因此没有无论如何都会重新排序.但是,我可能还误会了,是否可能意味着等价的组装件

I've been watching few talks to understand this ordering issue, I understand why it is important now. The thing I cannot quite figure yet how the compiler translates the order specification, I think also the example given by the documentation isn't particularly useful as well because after the store operation in the thread running producer there's no other instruction, hence nothing would be re-ordered anyway. However is also possible I'm missunderstanding, is it possible they mean that the equivalent assembly of

std::string* p  = new std::string("Hello");
data = 42;
ptr.store(p, std::memory_order_release);

会使得翻译后的前两行在原子存储之后永远不会移动吗? 同样,在运行线程的生产器中,是否有可能在原子加载之前没有断言(或等效程序集)被移动?假设我在存储之后有了第三条指令,那么这些指令将发生什么,而原子加载之后已经发生了什么?

will be such that the first two lines translated will never be moved after the atomic store? Likewise in the thread running producer is it possible that none of the asserts (or the equivalent assembly) will ever be moved before the atomic load? Suppose I had a third instruction after the store what would happen to those instruction instead which would be already after the atomic load?

我还尝试编译这样的代码以保存带有-S标志的中间汇编代码,但是它很大,我无法确定.

I've also tried to compile such code to save the intermediate assembly code with the -S flag, but it's quite large and I can't really figure.

再次要澄清的是,这个问题是关于排序的方式,而不是关于这些机制为何有用或必要的原因.

Again, to clarify, this question is about how the ordering, is not about why these mechanism are useful or necessary.

推荐答案

我知道,当涉及到内存排序时,人们通常会争辩是否可以对操作以及如何对操作进行重新排序,但是我认为这是错误的方法! C ++标准未说明如何对指令进行重新排序,而是定义了先发生关系,其本身基于先后顺序,同步和线程间先发生关系

I know that when it comes to memory orderings, people usually try to argue if and how operations can be reorder, but in my opinion this is the wrong approach! The C++ standard does not state how instructions can be reordered, but instead defines the happens-before relation, which itself is based on the sequenced-before, synchronize-with and inter-thread-happens-before relations.

获取负载,它从获取负载的存储版本同步读取值,因此建立了事前发生的关系.由于事前发生关系的可传递性,因此在存储释放之前"进行按先后顺序"的操作,也就在获取负载之前"进行在发生之前"的操作.关于使用原子实现的正确性的任何争论都应始终依赖于事前发生的关系. 是否以及如何对指令进行重新排序仅仅是对事前发生关系应用规则的结果.

An acquire-load that reads the value from a store-release sychronizes-with that acquire load, therefore establishing a happens-before relation. Due to the transitivity of the happens-before relation, operations that are "sequenced-before" the store-release, also "happen-before" the acquire-load. Any arguments about the correctness of an implementation using atomics should always rely on the happens-before relation. If and how instructions can be reordered is merely a result of applying the rules for the happens-before relation.

有关C ++内存模型的详细说明,请查看 C/C ++程序员的内存模型.

For a more detailed explanation of the C++ memory model you can take a look at Memory Models for C/C++ Programmers.

这篇关于std :: memory_order和指令顺序,澄清的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆