R. *_*des 57 c++ multithreading memory-model c++11
我一直在阅读有关新C++ 11内存模型的内容,并且我已经开始使用该std::kill_dependency功能(§29.3/ 14-15).我很难理解为什么我会想要使用它.
我在N2664提案中找到了一个例子,但它并没有多大帮助.
它首先显示代码而不是std::kill_dependency.这里,第一行将依赖性携带到第二行中,第二行将依赖性携带到索引操作中,然后将依赖性携带到do_something_with函数中.
r1 = x.load(memory_order_consume);
r2 = r1->index;
do_something_with(a[r2]);
Run Code Online (Sandbox Code Playgroud)
还有一个例子std::kill_dependency用于打破第二行和索引之间的依赖关系.
r1 = x.load(memory_order_consume);
r2 = r1->index;
do_something_with(a[std::kill_dependency(r2)]);
Run Code Online (Sandbox Code Playgroud)
据我所知,这意味着索引和调用do_something_with不是在第二行之前排序的依赖项.根据N2664:
这允许编译器将调用重新排序
do_something_with,例如,通过执行预测值的推测优化a[r2].
为了使得需要调用do_something_with该值a[r2].假设编译器"知道"数组填充了零,它可以根据需要优化该调用do_something_with(0);并相对于其他两个指令重新排序此调用.它可以产生以下任何一种:
// 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;
Run Code Online (Sandbox Code Playgroud)
我的理解是否正确?
如果do_something_with通过其他方式与另一个线程同步,这对于x.load调用的顺序和另一个线程意味着什么?
假设我的描述是正确的,那还有一件事让我感到困惑:当我编写代码时,是什么原因导致我选择杀死依赖?
bdo*_*lan 39
memory_order_consume的目的是确保编译器不会执行某些可能会破坏无锁算法的不幸优化.例如,考虑以下代码:
int t;
volatile int a, b;
t = *x;
a = t;
b = t;
Run Code Online (Sandbox Code Playgroud)
符合标准的编译器可以将其转换为:
a = *x;
b = *x;
Run Code Online (Sandbox Code Playgroud)
因此,a可能不等于b.它也可以:
t2 = *x;
// use t2 somewhere
// later
t = *x;
a = t2;
b = t;
Run Code Online (Sandbox Code Playgroud)
通过使用load(memory_order_consume),我们要求在使用点之前不要移动正在加载的值的使用.换一种说法,
t = x.load(memory_order_consume);
a = t;
b = t;
assert(a == b); // always true
Run Code Online (Sandbox Code Playgroud)
标准文档考虑了您可能只对订购结构的某些字段感兴趣的情况.例子是:
r1 = x.load(memory_order_consume);
r2 = r1->index;
do_something_with(a[std::kill_dependency(r2)]);
Run Code Online (Sandbox Code Playgroud)
这指示编译器允许它有效地执行此操作:
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
Run Code Online (Sandbox Code Playgroud)
甚至这个:
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);
Run Code Online (Sandbox Code Playgroud)
如果编译器知道do_something_with不会改变r1或r2的加载结果,那么它甚至可以将它一直提升:
do_something_with(a[x->index]); // completely unordered
r1 = x; // ordered
r2 = r1->index; // ordered
Run Code Online (Sandbox Code Playgroud)
这使编译器在优化方面有了更多的自由度.
Cor*_*ica 10
除了另一个答案之外,我还要指出,C++社区最权威的领导者之一Scott Meyers对memory_order_consume非常强烈.他基本上说他相信它在标准中没有位置.他说有两种情况,memory_order_consume有任何影响:
是的,再次,DEC Alpha通过使用在任何其他芯片中看不到的优化,直到多年后在荒谬的专业机器上找到它的方式.
特别的优化是那些处理器允许在实际获得该字段的地址之前取消引用字段(即,它甚至在使用x的预测值查找x之前查找x-> y).然后它返回并确定x是否是它预期的值.成功后,它节省了时间.失败时,它必须返回并再次获得x-> y.
Memory_order_consume告诉编译器/体系结构这些操作必须按顺序发生.但是,在最有用的情况下,最终会想要做(x-> yz),其中z不会改变.memory_order_consume将强制编译器按顺序保持xy和z.kill_dependency(x-> y).z告诉编译器/架构它可能会继续进行这种恶意的重新排序.
99.999%的开发人员可能永远不会在需要此功能的平台上工作(或者根本没有任何影响).