根据这个https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html,
已发布的商店在x86(包括x86-64)上实现为MOV
(进入内存)。
根据他的http://en.cppreference.com/w/cpp/atomic/memory_order
memory_order_release :
具有此内存顺序的存储操作会执行发布 操作:当前线程中的内存访问不能重新排序 在这家商店之后。这确保了当前线程中的所有写入 在获取或相同原子变量的其他线程中可见 并且将带有依赖关系的写入变为原子变量 在使用相同原子的其他线程中可见。
据我所知,当使用 memory_order_release 时,之前完成的所有内存存储都应该在此之前完成。
int a;
a = 10;
std::atomic<int> b;
b.store(50, std::memory_order_release); // i can be sure that 'a' is already 10, so processor can't reorder the stores to 'a' and 'b'
问题:裸MOV
指令(没有明确的内存栅栏)对于此行为是否足够? MOV
如何告诉处理器完成以前的所有商店?
答案 0 :(得分:5)
运行时有内存重新排序(由CPU完成),并且在编译时有内存重新排序。请阅读Jeff Preshing's article on compile-time reordering(以及该博客上的许多其他好文章)以获取更多信息。
memory_order_release
阻止编译器重新排序对数据的访问,以及发出任何必要的防护或特殊指令。在x86 asm中,普通的加载和存储已经具有获取/释放语义,因此阻塞编译时重新排序对于acq_rel而言是足够的,但不是seq_cst。
答案 1 :(得分:4)
这似乎是映射,至少在使用英特尔编译器编译的代码中,我看到:
0000000000401100 <_Z5storeRSt6atomicIiE>:
401100: 48 89 fa mov %rdi,%rdx
401103: b8 32 00 00 00 mov $0x32,%eax
401108: 89 02 mov %eax,(%rdx)
40110a: c3 retq
40110b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
0000000000401110 <_Z4loadRSt6atomicIiE>:
401110: 48 89 f8 mov %rdi,%rax
401113: 8b 00 mov (%rax),%eax
401115: c3 retq
401116: 0f 1f 00 nopl (%rax)
401119: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
代码:
#include <atomic>
#include <stdio.h>
void store( std::atomic<int> & b ) ;
int load( std::atomic<int> & b ) ;
int main()
{
std::atomic<int> b ;
store( b ) ;
printf("%d\n", load( b ) ) ;
return 0 ;
}
void store( std::atomic<int> & b )
{
b.store(50, std::memory_order_release ) ;
}
int load( std::atomic<int> & b )
{
int v = b.load( std::memory_order_acquire ) ;
return v ;
}
当前的Intel architecture documents,第3卷(系统编程指南),可以很好地解释这一点。参见:
8.2.2 P6和更近期处理器系列中的存储器排序
那里解释了完整的内存模型。我假设英特尔和C ++标准人员已经详细合作,以确定每个内存顺序操作的最佳映射,这符合第3卷中描述的内存模型,并确定了普通存储和负载在这些情况下就足够了。
请注意,仅仅因为x86-64上的此有序存储不需要特殊指令,并不意味着它将普遍存在。对于powerpc,我希望看到类似lwsync指令和存储的东西,而在hpux(ia64)上,编译器应该使用st4.rel指令。