对于我对在 Windows x64 上使用原子互锁操作不感兴趣的类型,是否可以诱导 std::atomic 输出 CMPXCHG16B,或者我只需要接受它并手动执行原子操作?我可以让 GCC/Clang 在 Linux 上执行此操作,所以我怀疑这只是 Microsoft 标准库的问题。
struct Byte16
{
int64_t a, b;
};
std::atomic<Byte16> atm;
Byte16 a = { 1, 2 };
atm.compare_exchange_strong(...); // This has a lock on Windows, not on Linux version of code
到了2024年,MSVC仍然不可能实现无锁
std::atomic<Byte16>
。
lock cmpxchg16b
的广泛可用性已经得到认可,但由于 VS 2015 和 VS 2022(以及中间的所有内容)之间的 ABI 兼容性,维护人员不可能重新定义 std::atomic
结构,直到下一次 ABI 更改为止。
但是,由于后来添加了
std::atomic_ref
,所以一开始就可以使用lock cmpxchg16b
。它仍然会根据 CPU 检查有条件地使用它。要绕过 CPU 检查,请将 _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B
定义为 1
进行编译。
如果您需要的是
std::atomic_ref
而不是 atomic
,则可以将 atomic_ref
与单个对象中的基础值捆绑在一起,如下所示:
template<class T>
struct atomic_x : std::atomic_ref<T>
{
template<class... A>
atomic_x(A ... a) : std::atomic_ref<T>(Value), Value(a...) {}
alignas(std::atomic_ref<T>::required_alignment) T Value;
};
演示:https://godbolt.org/z/jvqd3f71K
请注意,这样的 16 字节
std::atomic_ref
即使对于加载和存储也将 lock cmpxchg16b
。也许可以使它们简单地加载和存储 - 请参阅 SSE 指令:哪些 CPU 可以执行原子 16B 内存操作? - 但这还没有在 MSVC STL 中实现。
在 Windows 中使用 __m128
#include <emmintrin.h>
//...
std::atomic<__m128> a, c;
__m128 b;
a.compare_exchange_strong(b,c);
///...