`std :: kill_dependency`做什么,为什么要使用它呢? [英] What does `std::kill_dependency` do, and why would I want to use it?

查看:240
本文介绍了`std :: kill_dependency`做什么,为什么要使用它呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在阅读关于新的C ++ 11内存模型,我来了 std :: kill_dependency 函数(§ 29.3 / 14-15 )。我很难理解为什么我会使用它。

I've been reading about the new C++11 memory model and I've come upon the std::kill_dependency function (§29.3/14-15). I'm struggling to understand why I would ever want to use it.

我在 N2664提案,但它没有太大帮助。

I found an example in the N2664 proposal but it didn't help much.

它首先显示没有 std :: kill_dependency 的代码。这里,第一行在第二行中携带依赖性,其带有对索引操作的依赖性,然后将依赖性携带到 do_something_with 函数中。

It starts by showing code without std::kill_dependency. Here, the first line carries a dependency into the second, which carries a dependency into the indexing operation, and then carries a dependency into the do_something_with function.

r1 = x.load(memory_order_consume);
r2 = r1->index;
do_something_with(a[r2]);

还有另一个使用 std :: kill_dependency 破坏第二行和索引之间的依赖关系。

There is further example that uses std::kill_dependency to break the dependency between the second line and the indexing.

r1 = x.load(memory_order_consume);
r2 = r1->index;
do_something_with(a[std::kill_dependency(r2)]);

据我所知,这意味着索引和调用 do_something_with 在第二行之前没有依赖顺序。根据N2664:

As far as I can tell, this means that the indexing and the call to do_something_with are not dependency ordered before the second line. According to N2664:


这允许编译器将调用重新排序为 do_something_with 例如通过执行预测 a [r2] 的值的推测优化。

This allows the compiler to reorder the call to do_something_with, for example, by performing speculative optimizations that predict the value of a[r2].

为了调用 do_something_with ,需要值 a [r2] 。如果假设编译器知道数组用零填充,它可以优化对 do_something_with(0); 的调用,并相对于其他两个指令,因为它喜欢。它可以产生以下任意:

In order to make the call to do_something_with the value a[r2] is needed. If, hypothetically, the compiler "knows" that the array is filled with zeros, it can optimize that call to do_something_with(0); and reorder this call relative to the other two instructions as it pleases. It could produce any of:

// 1
r1 = x.load(memory_order_consume);
r2 = r1->index;
do_something_with(0);
// 2
r1 = x.load(memory_order_consume);
do_something_with(0);
r2 = r1->index;
// 3
do_something_with(0);
r1 = x.load(memory_order_consume);
r2 = r1->index;

我的理解是否正确?

do_something_with 通过其他方式与另一个线程同步,这对于 x.load 的顺序意味着什么,调用和这个其他线程?

If do_something_with synchronizes with another thread by some other means, what does this mean with respect to the ordering of the x.load call and this other thread?

假设我的转义是正确的,还有一件事是错误的:当我写代码时,什么原因导致我选择杀死依赖项?

Assuming my understading is correct, there's still one thing that bugs me: when I'm writing code, what reasons would lead me to choose to kill a dependency?

推荐答案

memory_order_consume的目的是确保编译器不做某些不幸的优化,例如,考虑下面的代码:

The purpose of memory_order_consume is to ensure the compiler does not do certain unfortunate optimizations that may break lockless algorithms. For example, consider this code:

int t;
volatile int a, b;

t = *x;
a = t;
b = t;


$ b

A conforming compiler may transform this into:

a = *x;
b = *x;

因此,a可能不等于b。它也可以:

Thus, a may not equal b. It may also do:

t2 = *x;
// use t2 somewhere
// later
t = *x;
a = t2;
b = t;

使用 load(memory_order_consume)要求正在加载的值的使用不会在使用点之前移动。换句话说,

By using load(memory_order_consume), we require that uses of the value being loaded not be moved prior to the point of use. In other words,

t = x.load(memory_order_consume);
a = t;
b = t;
assert(a == b); // always true

标准文档考虑的情况是,您可能只想订购某些字段结构。示例是:

The standard document considers a case where you may only be interested in ordering certain fields of a structure. The example is:

r1 = x.load(memory_order_consume);
r2 = r1->index;
do_something_with(a[std::kill_dependency(r2)]);

这指示编译器允许有效地执行此操作:

This instructs the compiler that it is allowed to, effectively, do this:

predicted_r2 = x->index; // unordered load
r1 = x; // ordered load
r2 = r1->index;
do_something_with(a[predicted_r2]); // may be faster than waiting for r2's value to be available

或者甚至:

predicted_r2 = x->index; // unordered load
predicted_a  = a[predicted_r2]; // get the CPU loading it early on
r1 = x; // ordered load
r2 = r1->index; // ordered load
do_something_with(predicted_a);



如果编译器知道 do_something_with t更改r1或r2的载荷结果,然后它可以将其一直向上抬起:

If the compiler knows that do_something_with won't change the result of the loads for r1 or r2, then it can even hoist it all the way up:

do_something_with(a[x->index]); // completely unordered
r1 = x; // ordered
r2 = r1->index; // ordered

这允许编译器在其优化中有一点自由。

This allows the compiler a little more freedom in its optimization.

这篇关于`std :: kill_dependency`做什么,为什么要使用它呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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