Ответ 1
[[carries_dependency]]
используется, чтобы позволить зависимостям переноситься через вызовы функций. Это потенциально позволяет компилятору генерировать лучший код при использовании с std::memory_order_consume
для передачи значений между потоками на платформах со слабоупорядоченными архитектурами, такими как архитектура IBM POWER.
В частности, если значение, считанное с помощью memory_order_consume
, передается функции, то без [[carries_dependency]]
, компилятору, возможно, придется выдать команду сохранения памяти, чтобы гарантировать, что соответствующая семантика упорядочения памяти будет поддержана. Если параметр аннотируется с помощью [[carries_dependency]]
, тогда компилятор может предположить, что тело функции будет правильно переносить зависимость, и этот забор больше не понадобится.
Аналогично, если функция возвращает значение, загруженное с помощью memory_order_consume
, или полученное из такого значения, то без [[carries_dependency]]
компилятору может потребоваться вставить команду ограждения, чтобы гарантировать, что соответствующая семантика упорядочения памяти будет поддержана. С аннотацией [[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
непрозрачно (если оно не указано), поэтому компилятор должен выдать забор, чтобы убедиться, что чтение *p
в print
возвращает правильное значение.
В строке (3) компилятор может предположить, что хотя print2
также непрозрачен, тогда зависимость от параметра до разыменованного значения сохраняется в потоке команд, и в POWER не требуется никакого забора. Очевидно, что определение print2
должно фактически сохранить эту зависимость, поэтому атрибут также повлияет на сгенерированный код для print2
.