我正在尝试实现一个简单的忙循环功能。
这应该继续轮询std :: atomic变量最大次数(spinCount),如果状态在给定的尝试内确实发生了变化(变为NOT_AVAILABLE以外的任何值),则返回true;否则返回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只是优化了Win64发行版上的循环。我对Assembly很不好,但是对我来说却根本不像尝试读取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 :: memory_order_sequential_cst的std :: atomic创建了一个编译器屏障,该屏障应防止出现这种情况,但事实并非如此(或者,我的理解可能是错误的)。
这是我在做什么错,或更确切地说,如何在不优化循环的情况下最好地实现该循环,而对整体性能的影响却最小?
我知道我可以使用#pragmaoptimize(“”,off),但是(除了上面的示例中),在我的最终代码中,出于性能原因,我非常希望将此调用内联到更大的函数中。似乎这个#pragma通常会阻止内联。
感谢任何想法!
谢谢
答案 0 :(得分:4)
但在我看来,它甚至根本都没有尝试读取
statusPtr
的值
它会在循环的每次迭代中重新加载它:
000000013F7E2048 mov r8d,dword ptr [rcx] # rcx is statusPtr
我的印象是
std::atomic
与std::memory_order_sequential_cst
会产生一个编译器障碍,应该防止出现这种情况,
这里您只需要std::memory_order_relaxed
就可以了,因为线程之间仅共享一个变量(甚至更多,此代码也不会更改atomic变量的值)。没有重新排序的问题。
换句话说,此功能可以正常工作。
您可能想使用PAUSE
指令,请参见Benefitting Power and Performance Sleep Loops。