Стандарт C ++ 11 определяет модель памяти (1.7, 1.10), которая содержит порядок памяти, который, грубо говоря, является «последовательно согласованным», «приобретать», «потреблять», «выпускать», и «расслаблен». В равной степени программа является правильной только в том случае, если она не содержит гонок, что происходит, если все действия могут быть расположены в некотором порядке, в котором одно действие происходит до другого. Способ, которым действие X происходит до действия Y, состоит в том, что либо X упорядочивается до Y (в пределах один поток), или X между потоками происходит до Y. Последнее условие дается, среди прочего, когда
- X синхронизируется с Y или
- X упорядочивается по зависимости перед Y.
Синхронизация с происходит, когда X - это атомарное хранилище с порядком выпуска для некоторой атомарной переменной, а Y - это атомарная загрузка с "заказ по той же переменной. Быть упорядоченным-зависимостью происходит для аналогичной ситуации, когда Y загружается с упорядочением «потребление» (и подходящим доступом к памяти). Понятие синхронизирует-с транзитивно расширяет связь происходит-до на действия, которые упорядочены-до друг друга в потоке, но являются dependency-order-before транзитивно расширяется только с помощью строгого подмножества sequence-before, называемого supports-dependency, которое следует обширному набору правил, и в частности, может быть прерван с помощью std::kill_dependency
.
Итак, какова цель понятия «упорядочение зависимостей»? Какое преимущество он дает по сравнению с более простым упорядочением упорядочено до / синхронизируется с? Поскольку правила для него более строгие, я предполагаю, что это можно реализовать более эффективно.
Можете ли вы привести пример программы, в которой переключение с выпуска / получения на выпуск / использование является правильным и дает нетривиальное преимущество? И когда std::kill_dependency
обеспечит улучшение? Аргументы высокого уровня были бы хороши, но бонусные баллы за аппаратные различия.
atomic<>
Разговоры об оружии, и он сказал, что не будет обсуждать потребление, потому что никто этого не понимает. - person Kerrek SB   schedule 26.10.2013memory_order_release
. Во время pop вы хотите иметь иtail
, иtail->value
, где загрузкаtail
несет-a-dependency-totail->value
, но вам все равно, поэтому вы можете использоватьmemory_order_consume
вместоmemory_order_acquire
. - person Evgeny Panasyuk   schedule 28.10.2013memory_order_acquire
- может быть лишним. - person Evgeny Panasyuk   schedule 28.10.2013memory_order
. Например, все побочные эффекты, которые происходят перед атомарной операцией сmemory_order_release
, должны быть видны любому потоку, который выполняет атомарную операцию с той же атомарной переменной сmemory_order_acquire
. Это может потребовать от ЦП выполнения таких действий, как очистка кешей, хотя обычно разработчики ЦП пытаются найти более эффективные решения, чем это. Для больших суперкомпьютеров стоит обратить внимание на пропускную способность соединений, используемых в этом процессе. - person Cort Ammon   schedule 14.06.2018lock
для поддержки шаблонов чтения-изменения-обновления, таких какatomic<int>::operator++
, которые включают как чтение, так и запись. Простые операции чтения или записи действительно являются атомарными (при разумных обстоятельствах). Вот чей-то ответ, который углубляется в это. Поведение архитектур, отличных от x86, - это, очевидно, совсем другой вопрос. - person Cort Ammon   schedule 14.06.2018volatile
является одной из таких функций). Это сообщение в блоге - мой любимый способ объяснить, насколько много может сделать компилятор, если вы явно не используете эти функции для ограничения его оптимизаций. - person Cort Ammon   schedule 15.06.2018