2011-06-20 48 views
63

有人能用一种凡人能理解的语言来解释吗?[[carry_dependency]]属性的含义是什么?

+4

HTTP内存(和心)的功能,一些大错误://www.open-std。org/jtc1/sc22/wg21/docs/papers/2008/n2643.html – DumbCoder

+1

@DumbCoder:谢谢,这绝对比N2390本身好,不幸的是它重定向到许多其他“理解这个提议所必需的”论文...似乎我的问题过于宽泛:) – ybungalobill

+1

在正常语言中,它是一个可选的优化提示(目前未实现或被每个编译器忽略),理论上可以让编译器在极少数情况下生成稍好的多线程代码修改后,经常读取的数据是共享的。好的工作,措辞如此扭曲,以至于没有人会永远使用它:-) – Damon

回答

51

[[carries_dependency]]用于允许在函数调用中执行依赖关系。这可能允许编译器在与std::memory_order_consume一起使用时生成更好的代码,以便在具有如IBM的POWER体系结构等微弱有序体系结构的平台上的线程之间传递值。

特别是,如果将使用memory_order_consume读取的值传递给函数,而没有使用[[carries_dependency]],那么编译器可能必须发出内存篱笆指令以保证适当的内存顺序语义得到支持。如果参数注释为[[carries_dependency]],那么编译器可以假定函数体将正确地携带依赖关系,并且此篱笆可能不再需要。同样,如果一个函数返回一个加载了memory_order_consume的值,或者从这个值派生,那么没有[[carries_dependency]],编译器可能需要插入一个fence指令来保证适当的内存顺序语义得到支持。使用[[carries_dependency]]批注时,可能不再需要此围栏,因为调用者现在负责维护依赖关系树。

例如

void print(int * val) 
{ 
    std::cout<<*p<<std::endl; 
} 

void print2(int * [[carries_dependency]] val) 
{ 
    std::cout<<*p<<std::endl; 
} 

std::atomic<int*> p; 
int* local=p.load(std::memory_order_consume); 
if(local) 
    std::cout<<*local<<std::endl; // 1 

if(local) 
    print(local); // 2 

if(local) 
    print2(local); // 3 

在线(1),相关性是显式的,所以编译器知道local被解除引用,而且它必须确保依赖关系链中,以避免在POWER围栏保存。

在线路(2)的print的定义是不透明的(假设它不是内联),因此编译器必须按顺序发出围栏,以确保在阅读print返回*p正确的值。

在第(3)行上,编译器可以假定虽然print2也是不透明的,但是从参数到解除引用值的依赖关系保存在指令流中,POWER上不需要栅栏。显然,print2的定义必须实际保留这种依赖关系,因此该属性也会影响生成的代码print2

+15

这是一个很好的答案。但是......你将如何编写函数来保存依赖关系?一个不正确编码的函数会是什么样的,结果会是什么? – Omnifarious

+2

顺便说一句,我收到了一本PDF格式的预发布副本。这是一本很棒的书。尽管如此,我真的希望你能够在一个接收电话的隐喻里把你的“人”放在一边。这是了解发生了什么的一个很好的工具。 – Omnifarious

+2

从源代码的POV中,只需要使用''[[carry_dependency]]'属性,而不是调用'std :: kill_dependency'。编译器将确保它不会中断生成的代码中的依赖关系链。 –

-2

简而言之,我认为,如果有carry_dependency属性,则应该为某个情况优化函数的生成代码,这时实际参数实际上来自另一个线程并且具有依赖关系。类似的返回值。如果这种假设不正确(例如在单线程程序中),则可能会缺乏性能。但是[[carry_dependency]]的缺失也可能导致相反情况下的糟糕表现...除了性能改变之外,没有其他影响会发生。

例如,指针取消引用操作取决于先前如何获得指针,并且如果指针p的值来自另一个线程(通过“消费”操作),那么先前由另一个线程分配给* p是考虑到和可见的。可能有另一个指针q等于p(q == p),但由于它的值不是来自其他线程,所以* q的值可能与* p不同。实际上,* q可能引发一种“未定义行为”(因为访问内存位置与另一个进行赋值的线程不协调)。

真的,似乎有在某些工程案例....> :-)

相关问题