Вам не нужно ничего делать, чтобы заблокировать переупорядочение во время компиляции;вызовы не встроенных функций - это черные ящики, которые могут взаимодействовать друг с другом через глобальные переменные, поэтому компилятор не может переупорядочить их.
Или, если std::chrono::steady_clock::now();
может полностью встроиться (возможно, используявстроенный asm для чтения метки времени), правильная реализация now()
будет использовать что-то вроде volatile
доступа или GNU C asm volatile
, чтобы убедиться, что он не может переупорядочиваться с другими вызовами now()
. (И что еще более важно, чтобы убедиться, что он не может быть CSE и быть выведенным из цикла, что приводит к иллюзии того, что все занимает ноль времени).
В отличие от вопроса, который вы связали, вещи, которые вызаботятся о порядке , а не простых вычислений, таких как z = x + y;
Это вызовы специальных функций, которые обычно являются библиотечными функциями. Я не проверял спецификации, но я не удивлюсь, если у функций, получающих время, есть какое-то правило о порядке упорядочения. друг с другом. Конечно, реализация хорошего качества захочет сделать это за вас.
Может ли процессор изменить порядок этих операций?
Это полу-plausible. В отличие от реальных реализаций, обычно now()
выполняет довольно много инструкций, сравнимых по размеру с окном выполнения вне порядка. (Например, размер ROB в 224 мопов на Skylake. Один rdtsc
- это только 20 мопов, и есть куча масштабирующих работ).
OoO exec обычно выполняется на основе самой старой готовности к началу, поэтому несколькоповторы той же функции now()
вряд ли будут работать не по порядку.
Если system_clock
и steady_clock
используют совершенно разные now
, а now
не делаетЧтобы не делать никаких барьеров, вы можете использовать механизм, специфичный для реализации, чтобы заблокировать OoO exec. например, на x86, _mm_lfence()
.
например, если system_clock
имеет низкие издержки now
, которые просто читают ячейку памяти volatile
(на странице, экспортируемой ядром, обновляемой обработчиком прерываний), но steady_clock::now
использует rdtsc
, изменение порядка возможно. Но нет никакого портативного способа остановить это.
Однако, согласно cppreference, «инструкции ЦП для упорядочения памяти не выдаются», поэтому я неясно, как это (atomic_signal_fence
) будетостановить процессор от переупорядочения вещей.
Это не так. Дело не в этом и не в чем оно. Внеочередное выполнение гарантирует сохранение иллюзии (для одного потока), что он выполнялся в программном порядке.
Следовательно, atomic_signal_fence
нужно только убедиться, что порядок программы asm соответствует исходному порядку исходного кода C ++. для обработчиков сигналов, работающих в одном потоке (или обработчиков прерываний на одном и том же ядре), чтобы наблюдать за операциями этого потока, происходящими в программном порядкеИли наоборот, для магазинов, созданных обработчиком сигнала.
Вы правы, что ваша попытка не сработает. Это могло бы помочь только в (IMHO сломанной) реализации, которая позволяла переупорядочивать функции во время компиляции now()
функций, и тогда, вероятно, только как побочный эффект от определения atomic_signal_fence()
. например, как что-то вроде GNU C asm volatile("":::"memory")
. Хотя, если now()
был сломан и использует оператор не-1062 * asm (поэтому множественные вызовы now()
могли бы CSE друг с другом), оператор asm volatile
не упорядочил бы их.