为什么<double>在使用 clang 编译时没有实现 std::atomic?

How come std::atomic<double> isn't implemented when compiling with clang?

本文关键字:实现 atomic std clang gt double lt 为什么 编译      更新时间:2023-10-16

考虑以下代码段:

#include <atomic>
int main(void) {
  std::atomic<double> aDouble;
  aDouble = 6.0;
}

G++编译得很好,而clang++产生以下内容:

clang++ -std=c++11 Main.cpp 
/tmp/Main-d4f0fc.o: In function `std::atomic<double>::store(double, std::memory_order)':
Main.cpp:(.text._ZNSt6atomicIdE5storeEdSt12memory_order[_ZNSt6atomicIdE5storeEdSt12memory_order]+0x31): undefined reference to `__atomic_store_8'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

它们不链接到同一个标准库吗?

如果

clang++ -stdlib=libstdc++不能解决您的问题,请链接到-latomic以实现这些函数。

但是,尝试让您的编译器内联 8 字节和更窄的原子学,因为库函数具有潜在的大缺点。

请注意,库函数不支持弱于memory_order_seq_cst的内存排序,因此它们始终在x86上使用mfence,即使源使用relaxed


32 位 x86 版本的 __atomic_store_8 甚至更糟:它使用 lock cmpxchg8b 而不是 SSE 或 x87 8 字节存储。 这使得它即使未对齐也能工作,但性能会受到巨大的损失。 它还有两个冗余lock or [esp], 0指令,作为从堆栈加载其参数的额外障碍。 (我正在查看 Arch Linux 上 gcc7.1.1 的/usr/lib32/libatomic.so.1.2.0

具有讽刺意味的是,当前的 gcc -m32(在 C11 模式下,而不是 C++11)在结构内部atomic_llong对齐不足,而是内联movq xmm加载/存储,因此它实际上不是原子的。 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65146#c4)

当前的clang -m32即使在结构内部也能atomic_llong到8个字节对齐(与常规long long不同,i386 System V ABI仅与4B对齐)。具有讽刺意味的是,clang 生成对库函数的调用,该函数使用 lock cmpxchg8b (https://bugs.llvm.org/show_bug.cgi?id=33109),因此即使使用缓存行拆分,它实际上也是原子的。(为什么在 x86 上自然对齐的变量上的整数赋值是原子的?

所以 clang 是安全的,即使一些 gcc 编译的代码向它传递指向未对齐_Atomic long long的指针。 但是它不同意 gcc 关于结构布局的观点,因此这只有在直接获得指向原子变量而不是包含结构的指针时才有帮助。


相关:原子双浮点或SSE/AVX矢量加载/存储在x86_64