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