回答此类问题的最简单方法通常是仅查看结果组装件,然后从那里取下组装件。
编译以下内容(我使您的结构更大,以躲避狡猾的编译器诡计):
#include <atomic>
struct foo {
double a;
double b;
double c;
double d;
double e;
};
std::atomic<foo> var;
void bar()
{
var.store(foo{1.0,2.0,1.0,2.0,1.0});
}
在clang 5.0.0中,在-O3下产生以下内容:在godbolt上参见
bar(): # @bar()
sub rsp, 40
movaps xmm0, xmmword ptr [rip + .LCPI0_0] # xmm0 = [1.000000e+00,2.000000e+00]
movaps xmmword ptr [rsp], xmm0
movaps xmmword ptr [rsp + 16], xmm0
movabs rax, 4607182418800017408
mov qword ptr [rsp + 32], rax
mov rdx, rsp
mov edi, 40
mov esi, var
mov ecx, 5
call __atomic_store
太好了,编译器将委托给一个内在(__atomic_store
),这并没有告诉我们这里到底发生了什么。但是,由于编译器是开源的,因此我们可以轻松地找到内在函数的实现(我在https://github.com/llvm-mirror/compiler-rt/blob/master/lib/builtins/atomic.c中找到了它的实现)):
void __atomic_store_c(int size, void *dest, void *src, int model) {
#define LOCK_FREE_ACTION(type) \
__c11_atomic_store((_Atomic(type)*)dest, *(type*)dest, model);\
return;
LOCK_FREE_CASES();
#undef LOCK_FREE_ACTION
Lock *l = lock_for_pointer(dest);
lock(l);
memcpy(dest, src, size);
unlock(l);
}
似乎魔术发生在中lock_for_pointer()
,所以让我们看一下:
static __inline Lock *lock_for_pointer(void *ptr) {
intptr_t hash = (intptr_t)ptr;
hash >>= 4;
intptr_t low = hash & SPINLOCK_MASK;
hash >>= 16;
hash ^= low;
return locks + (hash & SPINLOCK_MASK);
}
这是我们的解释:原子的地址用于生成哈希键以选择预先分配的锁。