C ++ 0X memory_order без заборов, приложений, чипов с поддержкой - PullRequest
6 голосов
/ 06 апреля 2011

Как следует из моего предыдущего вопроса , класс atomic<T> определяет большинство операций с параметром memory_order.В отличие от забора этот порядок памяти влияет только на атом, на котором он действует.Предположительно, используя несколько таких атомик, вы можете создать параллельный алгоритм, в котором упорядочение другой памяти неважно.

Поэтому у меня два вопроса:

  1. Может кто-нибудь указать мне на примералгоритм / ситуация, которая выиграла бы от упорядочения отдельных атомарных переменных, а не требует ограничений?
  2. Какие современные процессоры поддерживают этот тип поведения?То есть компилятор не просто переводит конкретный порядок в обычный забор.

1 Ответ

4 голосов
/ 06 апреля 2011

Параметр упорядочения памяти при операциях с std::atomic<T> переменными не влияет на упорядочение этой операции как таковой, он влияет на отношения упорядочения, которые операция создает с другими операциями.

напримерa.store(std::memory_order_release) сам по себе ничего не говорит о том, как операции на a упорядочены относительно чего-либо еще, но в паре с вызовом a.load(std::memory_order_acquire) из другого потока, тогда этот порядок других операций -- все записи в другие переменные (включая неатомарные), выполненные потоком, который сохранил a, видны потоку, который загрузил, если эта загрузка считывает сохраненное значение.

На современных процессорах некоторые упорядочения памяти для операций не выполняются.например, на x86 memory_order_acquire, memory_order_consume и memory_order_release подразумеваются в инструкциях загрузки и хранения и не требуют отдельных заборов.В этих случаях упорядочения просто влияют на переупорядочение команд, которое может выполнить компилятор.

Разъяснение: неявные ограничения в инструкциях могут означать, что компилятору не нужно выдавать любые явные инструкции ограничения, есливсе ограничения порядка памяти привязаны к отдельным операциям над атомарными переменными.Если вы используете memory_order_relaxed для всего и добавляете явные заборы, то компилятору, возможно, придется явно выдавать эти заборы как инструкции.

Например, на x86, инструкция XCHG несет с собой неявную memory_order_seq_cstзабор.Таким образом, нет никакой разницы между сгенерированным кодом для двух операций обмена ниже на x86 - они оба отображаются в одну XCHG инструкцию:

std::atomic<int> ai;
ai.exchange(3,std::memory_order_relaxed);
ai.exchange(3,std::memory_order_seq_cst);

Однако я пока не знаю ни о какихкомпилятор, который избавляется от явных инструкций забора в следующем коде:

std::atomic_thread_fence(std::memory_order_seq_cst);
ai.exchange(3,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);

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

Кроме того, std::memory_order_consume может только применяться к прямым операциям с переменными.

...