【发布时间】:2019-05-01 10:37:05
【问题描述】:
我正在尝试实现一个简单的忙循环功能。
这应该保持轮询 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::atomic 和 std::memory_order_sequential_cst 创建了一个编译器屏障,应该防止这样的事情,但似乎不是这样(或者更确切地说,我的理解可能是错误的)。
我在这里做错了什么,或者更确切地说 - 我怎样才能最好地实现该循环而不优化它,同时对整体性能的影响最小?
我知道我可以使用#pragma optimize("", off),但是(除了上面的示例),在我的最终代码中,出于性能原因,我非常希望将此调用内联到更大的函数中.似乎这个#pragma 通常会阻止内联。
欣赏任何想法!
谢谢
【问题讨论】:
标签: c++ multithreading visual-c++ atomic stdatomic