【发布时间】:2015-07-03 22:46:06
【问题描述】:
我有 64 位,我需要在事件之前非常快速地读取它们,然后在事件之后执行比较和交换。
我想我可以在活动之前加载(std::memory_order_relaxed)以快速阅读,然后在活动之后使用常规比较和交换。
当我比较非原子 64 位读取、原子(松弛)和原子(获取)之间的程序集时,我看不出程序集有任何区别。这是 C++ 测试:
int main(){
volatile uint64_t var2;
std::atomic<uint64_t> var; // The variable I wish to read quickly
var = 10;
var2 = var.load(std::memory_order_relaxed);
//var2 = var; // when var is not atomic
//var2 = var.load(std::memory_order_acquire); To see if the x86 changed
}
给出这个程序集:
!int main(){
main()+0: sub $0x48,%rsp
main()+4: callq 0x100401180 <__main>
! volatile uint64_t var2;
! volatile std::atomic<uint64_t> var;
! var = 10;
!
!
! var2 = var.load(std::memory_order_acquire);
main()()
main()+26: mov %rax,0x38(%rsp)
!
! int x;
! std::cin >> x;
main()+31: lea 0x2c(%rsp),%rdx
main()+36: mov 0x1f45(%rip),%rcx # 0x100403050 <__fu0__ZSt3cin>
main()+43: callq 0x100401160 <_ZNSirsERi>
!}main()+48: mov $0x0,%eax
main()+53: add $0x48,%rsp
main()+57: retq
显然使用std::memory_order_acquire 的程序集应该不同于读取的非原子变量?
这是因为读取 64 位是原子的,只要数据对齐,因此程序集没有什么不同?我会认为使用更强的内存屏障会插入围栏指令或其他东西?
我真正想知道的问题是,如果我将 64 位声明为原子并且我使用宽松的内存屏障进行读取,它是否会与读取非原子 64 位变量具有相同的性能成本?强>
【问题讨论】:
-
x86 处理器使用相当强的内存排序。我相信正常的加载和存储具有获取和释放语义,因此不需要围栏或其他特殊指令。其他 CPU 可能完全不同。特别是,有些人可能必须使用多条指令来读取 64 位值(例如 32 位 CPU),因此需要额外的同步指令才能以原子方式读取它。
-
这个问题很困惑。没有“宽松的记忆屏障”这样的东西。 C++ 定义了原子操作上的内存排序,它特定于一个内存位置,以及单独(几乎无用)的内存栅栏,你永远不会使用也不应该使用。
标签: c++ multithreading assembly atomic memory-barriers