3

我正在阅读Anthony Williams 的C++ Concurrency in Action。目前我在他描述memory_order_consume的地方。

在那个块之后有:

现在我已经介绍了内存排序的基础知识,是时候看看更复杂的部分了

这让我有点害怕,因为我不完全理解几件事:


之前的依赖排序与同步有什么不同?他们都创造了“事前发生”的关系。确切的区别是什么?


我对以下示例感到困惑:

int global_data[]={ … };
std::atomic<int> index;
void f()
{
    int i=index.load(std::memory_order_consume);
    do_something_with(global_data[std::kill_dependency(i)]);
}

kill_dependency 到底是做什么的?它杀死了哪个依赖?哪些实体之间?以及编译器如何利用这些知识?


memory_order_consume 的所有出现都可以安全地替换为 memory_order_acquire 吗?即它在所有意义上都更严格吗?


在代码清单 5.9 中,我可以安全地替换吗

std::atomic<int> data[5]; // all accesses are relaxed

int data[5]

? 即获取和释放可以用来同步访问非原子数据吗?


他通过一些小隔间里的男人的例子来描述放松、获得和释放。seq_cst和consume有没有类似的简单描述?

4

3 回答 3

4

至于倒数第二个问题,答案需要更多解释。当多个线程访问相同的数据时,可能会出现三件事:

  1. 系统可能会在读取或写入过程中切换线程,从而产生一半值和一半值的结果。

  2. 编译器可能会移动代码,假设没有其他线程查看所涉及的数据。

  3. 处理器可能会在其本地缓存中保留一个值,而不会在更改该值后更新主内存或在另一个线程更改主内存中的值后重新读取它。

内存顺序寻址数字 3。原子函数寻址 1 和 2,并且根据内存顺序参数,也可能是 3。所以 memory_order_relaxed 的意思是“不要打扰数字 3。代码仍然处理 1 和 2。在这种情况下,您将使用获取和释放来确保正确的内存排序。

于 2013-02-08T19:24:01.860 回答
2

memory_order_consume 要求原子操作发生在所有依赖于它的数据的非原子操作之前。数据依赖项是指在不使用该数据的情况下无法评估表达式的任何依赖项。例如,在 x->y 中,如果不先计算 x,就无法计算 x->y。

kill_dependency 是一个独特的功能。所有其他函数对其参数都有数据依赖性。Kill_dependency 明确没有。当您知道数据本身已经同步时,它会显示出来,但是您需要获取数据的表达式可能未同步。在您的示例中,允许 do_something_with 假设 globalldata[i] 的任何缓存值都可以安全使用,但 i 本身实际上必须是正确的原子值。

如果对数据的所有更改都通过匹配的 memory_order_release 正确释放,则memory_order_acquire 会更严格。

于 2013-09-04T04:20:26.190 回答
2

之前的依赖排序与同步有什么不同?

从 1.10/10 开始:“[注意:关系“之前是依赖排序的”类似于“同步于”,但使用发布/使用代替发布/获取。-结束注释]”。

kill_dependency 到底是做什么的?

一些编译器进行数据依赖性分析。也就是说,他们跟踪变量中值的变化,以便更好地确定必须同步的内容。kill_dependency告诉此类编译器不要进一步跟踪,因为代码中发生了编译器无法理解的事情。

memory_order_consume 的所有出现都可以安全地替换为 memory_order_acquire 吗?即它在所有意义上都更严格吗?

我想是的,但我不确定。

于 2013-02-08T19:17:22.143 回答