Я пытаюсь реализовать простую функцию цикла занятости.
Это должно продолжать опрашивать переменную std::atomic максимальное количество раз (spinCount) и возвращать true, если статус действительно изменился (на что-либо, кроме NOT_AVAILABLE) в течение заданных попыток, или false в противном случае:
// noinline is just to be able to inspect the resulting ASM a bit easier - in final code, this function SHOULD be inlined!
__declspec(noinline) static bool trySpinWait(std::atomic<Status>* statusPtr, const int spinCount)
{
int iSpinCount = 0;
while (++iSpinCount < spinCount && statusPtr->load() == Status::NOT_AVAILABLE);
return iSpinCount == spinCount;
}
Однако кажется, что MSVC просто оптимизирует петлю в режиме Release для Win64. Я довольно плохо разбираюсь в сборке, но мне не кажется, что она когда-либо даже пытается прочитать значение statusPtr:
int iSpinCount = 0;
000000013F7E2040 xor eax,eax
while (++iSpinCount < spinCount && statusPtr->load() == Status::NOT_AVAILABLE);
000000013F7E2042 inc eax
000000013F7E2044 cmp eax,edx
000000013F7E2046 jge trySpinWait+12h (013F7E2052h)
000000013F7E2048 mov r8d,dword ptr [rcx]
000000013F7E204B test r8d,r8d
000000013F7E204E je trySpinWait+2h (013F7E2042h)
return iSpinCount == spinCount;
000000013F7E2050 cmp eax,edx
000000013F7E2052 sete al
У меня сложилось впечатление, что std::atomic с std::memory_order_sequential_cst создает барьер компилятора, который должен предотвратить что-то подобное, но, похоже, это не так (вернее, мое понимание, вероятно, было неверным).
Что я здесь делаю неправильно, или, скорее, как мне лучше всего реализовать этот цикл, не оптимизируя его, с наименьшим влиянием на общую производительность?
Я знаю, что мог бы использовать #pragma optim( "", off ), но (кроме приведенного выше примера) в моем окончательном коде я бы очень хотел, чтобы этот вызов был встроен в более крупную функцию по соображениям производительности. кажется, что эта #pragma обычно предотвращает встраивание.
Цените любые мысли!
Спасибо