Я нашел эту функцию в GitHub РЕПО который реализует очередь без блокировки. Эта функция использует QueryPerformanceCounter
чтобы получить точное системное время.
#define CompilerMemBar() std::atomic_signal_fence(std::memory_order_seq_cst)
SystemTime getSystemTime()
{
LARGE_INTEGER t;
CompilerMemBar();
if (!QueryPerformanceCounter(&t)) {
return static_cast<SystemTime>(-1);
}
CompilerMemBar();
return static_cast<SystemTime>(t.QuadPart);
}
Я заметил, что есть два CompilerMemBar()
Я подумал, что это предотвращает переупорядочивание компилятора. Однако после того, как я искал некоторые коды на github, я нашел обертку QueryPerformanceCounter
с барьерами компилятора не может быть обычной практикой. Итак, мой вопрос — эти барьеры здесь для решения каких-то особых ситуаций? Может быть, возможное изменение порядка повлияет на точность получаемого нами системного времени? Но я не могу понять, как они это сделают, потому что я думаю, что даже вызов WINAPI или оператор return переупорядочен, это, похоже, не влияет на точность.
Разработчик кода мог полагать, что он даст более точные результаты, если компилятор не сможет переупорядочить операторы.
Например:
expensive1(); // takes a lot of time
SystemTime t = getSystemTime();
expensive2();
Если вам нужна точная временная метка (или счетчик производительности) между обоими дорогостоящими вызовами, вы не хотите, чтобы компилятор переупорядочивал getSystemTime()
с одним из них
потому что это может повлиять на значение, возвращаемое QueryPerformanceCounter
,
Реально ли это, я не знаю. Компилятор должен знать, что происходит внутри функции, иначе он не будет ничего переупорядочивать
(если expensive
вызовы определяются в предварительно скомпилированной библиотеке, в любом случае переупорядочение операторов не будет выполняться).
Но, по крайней мере, такой подход, кажется, не приносит большого вреда.
std::atomic_signal_fence(std::memory_order_seq_cst)
предотвращает переупорядочение компилятора, но не выдает команды на забор процессора.
Других решений пока нет …