Почему memory_order задается в качестве аргумента времени выполнения для функций std :: atomic

std::atomic такие функции, как store а также load принять std::memory_order аргумент. Аргумент может быть определен во время выполнения, как и любой другой аргумент функции. Однако фактическое значение может повлиять на оптимизацию кода во время компиляции. Учтите следующее:

std::atomic<int> ai1, ai2;
int value = whatever;

void foo() {
std::memory_order memOrd = getMemoryOrder();
register int v = value; // load value from memory
ai1.store(v, memOrd);   // dependency on v's value
ai2.store(1, memOrd);   // no dependency. could this be move up?
}

Если memOrd бывает memory_order_relaxedВторой магазин может быть безопасно перемещен перед первым. Это добавит дополнительную работу между загрузкой value и использовать его, что может предотвратить иные требуемые срывы. Однако если memOrd является memory_order_seq_cstпереключение хранилищ не должно быть разрешено, потому что некоторые другие потоки могут рассчитывать на ai1 уже настроен на value если ai2 установлено на 1.

Мне интересно, почему порядок памяти был определен как аргумент времени выполнения, а не время компиляции. Есть ли причина, по которой кто-то должен исследовать среду во время выполнения, прежде чем выбирать лучшую семантику операций с памятью?

16

Решение

причина это реализовано как параметр времени выполнения, а не параметр времени компиляции для включения композиции.

Предположим, вы пишете функцию, которая использует предоставленные атомарные операции для выполнения эквивалента нагрузка операция, но работает на более высоком уровне конструкции. При наличии порядка памяти, заданного в качестве параметра времени выполнения, загрузка более высокого уровня может затем передать параметр порядка памяти, предоставленный пользователем, на атомарную операцию низкого уровня, которая требуется для обеспечения упорядочения без операции более высокого уровня, которая должна быть шаблоном.

Как правило, атомарные инструкции будут встроенными, и компилятор исключит проверку параметра порядка в памяти в случае, если это фактически константа времени компиляции.

6

Другие решения

Это просто спецификация интерфейса, которая позволяет memory_order быть указанным во время выполнения. Это не требует реализации для использования этого разрешения.

Например, на оборудовании x86 memory_order_seq_cst вероятно то, что вы получаете, что бы вы ни указали. memory_order_relaxed просто не доступен из-за протокола когерентности аппаратного кэша.

На другом оборудовании, где вы могли бы оптимизировать для известного порядка времени компиляции, реализация может предложить дополнительные перегрузки, которые используют параметры по умолчанию.

4

Авторы C ++ могли реализовать memory_order как функцию времени компиляции, а не функцию времени выполнения. Однако они бы ничего не получили за это. Любой компилятор, способный понимать порядки памяти, будет легко оптимизировать очевидные случаи, такие как x.load (memory_order_acq), поэтому они не выиграют от того, что это функция времени компиляции.

Между тем, использование функции времени выполнения означает, что им не нужно вводить какие-либо новые обозначения для порядков памяти. Они просто аргументы функции. Это означает, что они получили те же преимущества, что и версия времени компиляции, с меньшей сложностью.

Между тем, это очень удобно для более простых компиляторов, потому что они могут реализовать атомарный как обычный класс, не обращаясь к нему специально.

T atomic<T>::compare_exchange_strong(T& compare, T exchange, memory_order order)
{
lockBeforeUsing(order); // handle the acquire part of the memory order
if (mValue == compare) {
compare = mValue;
mValue = compare;
} else {
compare = mValue;
}
lockAfterUsing(order); // handle the release part of the memory order
}
0
По вопросам рекламы [email protected]