有人能用凡人能听懂的语言解释一下吗?
[[carries_dependency]]用于允许在函数调用之间传递依赖关系。这可能允许编译器在与 std::memory_order_consume一起使用时生成更好的代码,以便在具有弱序架构(如 IBM 的 POWER 架构)的平台上在线程之间传输值。
[[carries_dependency]]
std::memory_order_consume
特别是,如果一个用 memory_order_consume读取的值被传递给一个函数,那么没有 [[carries_dependency]],那么编译器可能必须发出一个内存隔离指令来保证支持适当的内存排序语义。如果参数是用 [[carries_dependency]]注释的,那么编译器可以假设函数体将正确地携带依赖项,并且这个栅栏可能不再是必需的。
memory_order_consume
类似地,如果一个函数返回一个加载了 memory_order_consume的值,或者从这个值派生出来的值,那么如果没有 [[carries_dependency]],编译器可能需要插入一个篱笆指令来保证支持适当的内存排序语义。使用 [[carries_dependency]]注释,这个栅栏可能不再是必需的,因为调用者现在负责维护依赖树。
例如:。
void print(int * val) { std::cout<<*val<<std::endl; } void print2(int * [[carries_dependency]] val) { std::cout<<*val<<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 上出现隔离。
local
在第(2)行中,print的定义是不透明的(假设它不是内联的) ,因此编译器必须发出一个篱笆,以确保读取 print中的 *p返回正确的值。
print
*p
在第(3)行,编译器可以假设,虽然 print2也是不透明的,但是指令流中保留了从参数到解引用值的依赖关系,而且在 POWER 上不需要栅栏。显然,print2的定义实际上必须保留这个依赖项,因此该属性还将影响为 print2生成的代码。
print2
简而言之,我认为,如果存在进行 _ 依赖性属性,那么应该针对实际情况对函数生成的代码进行优化,因为实际参数将真正来自另一个线程并进行依赖性。对于返回值也是如此。如果这个假设不成立(例如在单线程程序中) ,可能会缺乏性能。但是,在相反的情况下,[[进行 _ 依赖]]的缺失也可能导致糟糕的性能... ... 除了性能改变之外,不会发生其他影响。
例如,指针解引用操作取决于先前如何获得指针,如果指针 p 的值来自另一个线程(通过“使用”操作) ,那么先前分配给 * p 的另一个线程的值将被考虑在内并且是可见的。可能还有另一个指针 q 等于 p (q = = p) ,但是由于它的值不是来自另一个线程,所以 * q 的值可能与 * p 不同。实际上 * q 可能会引起某种“未定义行为”(因为访问内存位置与另一个进行赋值的线程不协调)。
实际上,在某些工程案例中,记忆(和思维)的功能似乎存在一些大的缺陷... . > : -)