谁能告诉我std :: atomic :: is_lock_free()是否像constexpr一样不是静态的?使它为非静态和/或为非constexpr对我来说没有意义。
谁能告诉我std :: atomic :: is_lock_free()是否像constexpr一样不是静态的?使它为非静态和/或为非constexpr对我来说没有意义。
Answers:
如对cppreference的解释:
除std :: atomic_flag以外的所有原子类型都可以使用互斥锁或其他锁定操作来实现,而不是使用无锁原子CPU指令来实现。原子类型有时也可以是无锁的,例如,如果在给定的体系结构上,只有对齐的内存访问自然是原子的,则相同类型的未对齐对象必须使用锁。
C ++标准建议(但不要求)无锁原子操作也无地址,也就是说,适用于使用共享内存的进程之间的通信。
正如其他许多人提到的那样,std::is_always_lock_free
可能正是您真正想要的。
编辑:明确起见,C ++对象类型具有一个对齐值,该对齐值将其实例的地址限制为仅2的幂的某些倍数[basic.align]
。这些对齐值是针对基本类型的实现定义的,不需要等于类型的大小。它们也可能比硬件实际支持的条件更严格。
例如,x86(大多数情况下)支持不对齐的访问。但是,您会发现大多数alignof(double) == sizeof(double) == 8
x86 编译器都具有x86,因为未对齐的访问具有许多缺点(速度,缓存,原子性...)。但是,例如#pragma pack(1) struct X { char a; double b; };
或alignas(1) double x;
允许您具有“ unaligned” double
。因此,当cppreference谈论“对齐的内存访问”时,大概是根据硬件类型的自然对齐方式进行的,而不是以与其对齐要求(即UB)相抵触的方式使用C ++类型。
这是更多信息:在x86上成功进行未对齐访问的实际影响是什么?
还请在下面查看@Peter Cordes的有见地的评论!
alignof(double)==4
。但是std::atomic<double>
仍然alignof() = 8
没有在运行时检查对齐方式。使用原子未对齐的压缩结构会破坏ABI,因此不受支持。(适用于32位x86的GCC倾向于自然对齐8字节对象,但结构打包规则会覆盖该对齐方式,并且仅基于alignof(T)
,例如基于i386 SystemV。G ++曾经存在一个错误,其中atomic<int64_t>
结构内部可能不是原子的因为它只是假设而已。GCC(对于C而不是C ++)仍然存在此错误!)
std::atomic_ref<double>
将要么double
完全拒绝未对齐的内容,要么在运行时在合法的平台上检查对齐情况,该平台应为纯文本double
并int64_t
小于自然对齐的地方。(因为atomic_ref<T>
在声明为普通对象的对象上进行操作T
,并且其最小对齐方式为,alignof(T)
没有机会对其进行额外对齐。)
_Atomic int64_t
用当前编译时显示撕裂了gcc -m32
。无论如何,我的观点是,真正的编译器不支持未对齐的原子,也不进行运行时检查(还可以吗?),所以#pragma pack
还是__attribute__((packed))
会导致非原子性;对象仍会报告它们是lock_free
。
is_lock_free()
是允许实现与当前的实现方式不同。通过基于实际对齐的运行时检查来使用硬件支持的原子指令或使用锁。
您可以使用 std::is_always_lock_free
is_lock_free
取决于实际系统,无法在编译时确定。
相关说明:
原子类型有时也可以是无锁的,例如,如果在给定的体系结构上,只有对齐的内存访问自然是原子的,则相同类型的未对齐对象必须使用锁。
std::numeric_limits<int>::max
取决于体系结构,但是是静态和constexpr
。我猜答案没有错,但是我不购买推理的第一部分
is_lock_free
是毫无意义上的编译器。
我已经在Windows PC上安装了Visual Studio 2019,并且该devenv也具有ARMv8编译器。ARMv8允许未对齐的访问,但是比较和交换,锁定的添加等必须进行对齐。并且还纯加载/存储纯使用ldp
或stp
(负载对或商店对32位寄存器)只保证是原子时,他们自然对齐。
因此,我编写了一个小程序来检查is_lock_free()返回的任意原子指针。所以这是代码:
#include <atomic>
#include <cstddef>
using namespace std;
bool isLockFreeAtomic( atomic<uint64_t> *a64 )
{
return a64->is_lock_free();
}
这是isLockFreeAtomic的反汇编
|?isLockFreeAtomic@@YA_NPAU?$atomic@_K@std@@@Z| PROC
movs r0,#1
bx lr
ENDP
这就是returns true
,又名1
。
该实现选择使用,alignof( atomic<int64_t> ) == 8
以便每个atomic<int64_t>
都正确对齐。这避免了对每个加载和存储进行运行时对齐检查的需要。
(编者注:这很常见;大多数现实生活中的C ++实现std::is_always_lock_free
都是以这种方式工作的。这就是为什么如此有用:因为通常对于类型为true的类型is_lock_free()
都是正确的。)
atomic<uint64_t>
,alignof() == 8
因此它们不必在运行时检查对齐方式。这个旧的API给他们提供了不这样做的选项,但是在当前的HW中,仅要求对齐(否则UB,例如非原子性)就更有意义了。即使在int64_t
可能只有4字节对齐的32位代码中,也atomic<int64_t>
需要8字节。请参阅我对另一个答案的评论
alignof
基本类型的值与硬件的“良好”对齐相同,那么 is_lock_free
它将始终是true
(也是is_always_lock_free
)。您的编译器正是在执行此操作。但是该API存在,因此其他编译器可以做不同的事情。
alignof(std::atomic<double>) == 1
(因此,即使硬件只能保证double
4或4上s 的无锁原子操作,C ++也不会有“未对齐的访问”,因此没有UB)。8个字节边界。然后,编译器将不得不在未对齐的情况下使用锁(并is_lock_free
根据对象实例的存储位置从中返回适当的布尔值)。
is_always_lock_free
吗?