gpt4 book ai didi

c++ - 改进 InterlockedCompareExchange() 的原子读取

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:04:18 28 4
gpt4 key购买 nike

假设架构是 ARM64 或 x86-64。

我想确定这两个是否等价:

  1. a = _InterlockedCompareExchange64((__int64*)p, 0, 0);
  2. MyBarrier(); a = *(volatile __int64*)p; MyBarrier();

其中 MyBarrier() 是编译器级别的内存屏障(提示),如 __asm__ __volatile__ (""::::"memory")。所以方法 2 应该比方法 1 更快。

我听说 _Interlocked() 函数也意味着编译器和硬件级别的内存屏障。

我听说读取(适当对齐的)内部数据在这些架构上是原子的,但我不确定方法 2 是否可以广泛使用?

(ps. 因为我认为 CPU 会自动处理数据依赖性,所以这里没有过多考虑硬件障碍。)

感谢您对此的任何建议/更正


以下是 Ivy Bridge(i5 笔记本电脑)上的一些基准测试。

(1E+006 循环:27ms):

; __int64 a = _InterlockedCompareExchange64((__int64*)p, 0, 0);
xor eax, eax
lock cmpxchg QWORD PTR val$[rsp], rbx

(1E+006 循环:27ms):

; __faststorefence(); __int64 a = *(volatile __int64*)p;
lock or DWORD PTR [rsp], 0
mov rcx, QWORD PTR val$[rsp]

(1E+006 循环:7ms):

; _mm_sfence(); __int64 a = *(volatile __int64*)p;
sfence
mov rcx, QWORD PTR val$[rsp]

(1E+006 循环:1.26ms,不同步?):

; __int64 a = *(volatile __int64*)p;
mov rcx, QWORD PTR val$[rsp]

最佳答案

要使第二个版本在功能上等效,您显然需要原子 64 位读取,这在您的平台上是正确的。

但是,_MemoryBarrier() 不是“对编译器的提示”。 x86 上的 _MemoryBarrier() 可防止编译器和 CPU 重新排序,并确保写入后的全局可见性。您也可能只需要第一个 _MemoryBarrier(),第二个可以用 _ReadWriteBarrier() 代替,除非 a 也是一个共享变量- 但你甚至不需要它,因为你正在读取一个 volatile 指针,这将阻止任何编译器在 MSVC 中重新排序。

当你创建这个替换时,你基本上最终会得到 same result :

// a = _InterlockedCompareExchange64((__int64*)&val, 0, 0);
xor eax, eax
lock cmpxchg QWORD PTR __int64 val, r8 ; val

// _MemoryBarrier(); a = *(volatile __int64*)&val;
lock or DWORD PTR [rsp], r8d
mov rax, QWORD PTR __int64 val ; val

在我的 i7 Ivy Bridge 笔记本电脑上循环运行这两个,得到相同的结果,在 2-3% 以内。

但是,有两个内存障碍,“优化版本”实际上慢了大约 2 倍。

所以更好的问题是:您为什么要使用 _InterlockedCompareExchange64如果您需要对变量进行原子访问,请使用 std::atomic,优化编译器应将其编译为最适合您的体系结构的版本,并添加所有必要的屏障以防止重新排序并确保缓存一致性。

关于c++ - 改进 InterlockedCompareExchange() 的原子读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53426225/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com