总结 :我本来以为std::atomic<int*>::load
与std::memory_order_relaxed
将接近的只是直接加载一个指针,至少当负载值很少改变的性能。 我看到了比在Visual Studio的C ++ 2012正常负荷的原子负荷差远了性能,所以我决定调查。 事实证明,原子负载为实现比较并交换循环,我怀疑是不是最快的可能的实现。
问 :有一些原因std::atomic<int*>::load
需要做一个比较并交换循环?
背景 :我认为MSVC ++ 2012正在做基于这个测试程序指针的原子负载比较并交换循环:
#include <atomic>
#include <iostream>
template<class T>
__declspec(noinline) T loadRelaxed(const std::atomic<T>& t) {
return t.load(std::memory_order_relaxed);
}
int main() {
int i = 42;
char c = 42;
std::atomic<int*> ptr(&i);
std::atomic<int> integer;
std::atomic<char> character;
std::cout
<< *loadRelaxed(ptr) << ' '
<< loadRelaxed(integer) << ' '
<< loadRelaxed(character) << std::endl;
return 0;
}
我使用__declspec(noinline)
函数以分离相关的原子负荷组装说明。 我做了一个新的MSVC ++ 2012项目,增加了一个x64平台,选择发布配置,在调试器中运行程序,看着拆卸。 原来,这两个std::atomic<char>
和std::atomic<int>
参数,最终给同一个呼叫loadRelaxed<int>
-这一定有什么优化做到了。 下面是两个loadRelaxed实例是得到所谓的拆卸:
loadRelaxed<int * __ptr64>
000000013F4B1790 prefetchw [rcx]
000000013F4B1793 mov rax,qword ptr [rcx]
000000013F4B1796 mov rdx,rax
000000013F4B1799 lock cmpxchg qword ptr [rcx],rdx
000000013F4B179E jne loadRelaxed<int * __ptr64>+6h (013F4B1796h)
loadRelaxed<int>
000000013F3F1940 prefetchw [rcx]
000000013F3F1943 mov eax,dword ptr [rcx]
000000013F3F1945 mov edx,eax
000000013F3F1947 lock cmpxchg dword ptr [rcx],edx
000000013F3F194B jne loadRelaxed<int>+5h (013F3F1945h)
该指令lock cmpxchg
是原子比较并交换和我们在这里看到,原子加载代码char
,一个int
或int*
是一个比较并交换循环。 我还内置此代码为32位x86和执行仍是基于lock cmpxchg
。
问 :有一些原因std::atomic<int*>::load
需要做一个比较并交换循环?