简体   繁体   English

为什么 std::atomic<t> ::is_lock_free() 不是 static 和 constexpr?</t>

[英]Why is std::atomic<T>::is_lock_free() not static as well as constexpr?

Can anyone tell me whether std::atomic::is_lock_free() isn't static as well as constexpr?谁能告诉我 std::atomic::is_lock_free() 不是 static 和 constexpr 吗? Having it non-static and / or as non-constexpr doesn't make sense for me.让它非静态和/或非 constexpr 对我来说没有意义。

As explained on cppreference :cppreference中所述:

All atomic types except for std::atomic_flag may be implemented using mutexes or other locking operations, rather than using the lock-free atomic CPU instructions.除了 std::atomic_flag 之外的所有原子类型都可以使用互斥锁或其他锁定操作来实现,而不是使用无锁原子 CPU 指令。 Atomic types are also allowed to be sometimes lock-free, eg if only aligned memory accesses are naturally atomic on a given architecture, misaligned objects of the same type have to use locks.原子类型有时也可以是无锁的,例如,如果仅对齐的 memory 访问在给定架构上自然是原子的,则相同类型的未对齐对象必须使用锁。

The C++ standard recommends (but does not require) that lock-free atomic operations are also address-free, that is, suitable for communication between processes using shared memory. C++ 标准建议(但不要求)无锁原子操作也是无地址的,即适用于使用共享 memory 的进程之间的通信。

As mentioned by multiple others, std::is_always_lock_free might be what you are really looking for.正如其他人所提到的, std::is_always_lock_free可能是您真正想要的。


Edit: To clarify, C++ object types have an alignment value that restricts the addresses of their instances to only certain multiples of powers of two ( [basic.align] ).编辑:澄清一下,C++ object 类型具有 alignment 值,该值将其实例的地址限制为仅是 2 的某些幂的倍数( [basic.align] )。 These alignment values are implementation-defined for fundamental types, and need not equal the size of the type.这些 alignment 值是针对基本类型的实现定义的,不需要等于类型的大小。 They can also be more strict than what the hardware could actually support.它们也可能比硬件实际支持的更严格。

For example, x86 (mostly) supports unaligned accesses.例如,x86(大部分)支持非对齐访问。 However, you will find most compilers having alignof(double) == sizeof(double) == 8 for x86, as unaligned accesses have a host of disadvantages (speed, caching, atomicity...).但是,您会发现大多数编译器对于 x86 具有alignof(double) == sizeof(double) == 8 ,因为未对齐的访问有许多缺点(速度、缓存、原子性......)。 But eg #pragma pack(1) struct X { char a; double b; };但是例如#pragma pack(1) struct X { char a; double b; }; #pragma pack(1) struct X { char a; double b; }; or alignas(1) double x;alignas(1) double x; allows you to have "unaligned" double s.允许您拥有“未对齐”的double s。 So when cppreference talks about "aligned memory accesses", it presumably does so in terms of the natural alignment of the type for the hardware, not using a C++ type in a way that contradicts its alignment requirements (which would be UB). So when cppreference talks about "aligned memory accesses", it presumably does so in terms of the natural alignment of the type for the hardware, not using a C++ type in a way that contradicts its alignment requirements (which would be UB).

Here is more information: What's the actual effect of successful unaligned accesses on x86?这里有更多信息: 成功的非对齐访问对 x86 的实际影响是什么?

Please also check out the insightful comments by @Peter Cordes below!还请查看下面@Peter Cordes的富有洞察力的评论!

You may use std::is_always_lock_free您可以使用std::is_always_lock_free

is_lock_free depends on the actual system and can't be determined at compile time. is_lock_free取决于实际系统,无法在编译时确定。

Relevant explanation:相关解释:

Atomic types are also allowed to be sometimes lock-free, eg if only aligned memory accesses are naturally atomic on a given architecture, misaligned objects of the same type have to use locks.原子类型有时也可以是无锁的,例如,如果仅对齐的 memory 访问在给定架构上自然是原子的,则相同类型的未对齐对象必须使用锁。

I've got installed Visual Studio 2019 on my Windows-PC and this devenv has also an ARMv8-compiler.我已经在我的 Windows-PC 上安装了 Visual Studio 2019,这个 devenv 也有一个 ARMv8 编译器。 ARMv8 allows unaligned accesses, but compare and swaps, locked adds etc. are mandated to be aligned. ARMv8 允许非对齐访问,但比较和交换、锁定添加等都必须对齐。 And also pure load / pure store using ldp or stp (load-pair or store-pair of 32-bit registers) are only guaranteed to be atomic when they're naturally aligned.而且,使用ldpstp (32 位寄存器的加载对或存储对)的纯加载/纯存储仅在它们自然对齐时才能保证是原子的。

So I wrote a little program to check what is_lock_free() returns for an arbitrary atomic-pointer.所以我写了一个小程序来检查 is_lock_free() 为任意原子指针返回什么。 So here's the code:所以这里是代码:

#include <atomic>
#include <cstddef>

using namespace std;

bool isLockFreeAtomic( atomic<uint64_t> *a64 )
{
    return a64->is_lock_free();
}

And this is the disassembly of isLockFreeAtomic这是 isLockFreeAtomic 的反汇编

|?isLockFreeAtomic@@YA_NPAU?$atomic@_K@std@@@Z| PROC
    movs        r0,#1
    bx          lr
ENDP

This is just returns true , aka 1 .这只是returns true ,也就是1

This implementation chooses to use alignof( atomic<int64_t> ) == 8 so every atomic<int64_t> is correctly aligned.此实现选择使用alignof( atomic<int64_t> ) == 8 ,因此每个atomic<int64_t>都正确对齐。 This avoids the need for runtime alignment checks on every load and store.这避免了运行时 alignment 检查每次加载和存储的需要。

(Editor's note: this is common; most real-life C++ implementations work this way. This is why std::is_always_lock_free is so useful: because it's usually true for types where is_lock_free() is ever true.) (编者注:这很常见;大多数现实生活中的 C++ 实现都是这样工作的。这就是std::is_always_lock_free如此有用的原因:因为它通常适用于is_lock_free()永远为真的类型。)

std::atomic<T>::is_lock_free() may in some implementations return true or false depending on runtime conditions. std::atomic<T>::is_lock_free()在某些实现中可能会根据运行时条件返回truefalse

As pointed out by Peter Cordes in comments, the runtime conditions cannot be alignment, as atomic will (over-)align internal storage for efficient lock-free operations, and forcing misalignment is UB that may manifest as loss of atomicity.正如 Peter Cordes 在评论中指出的那样,运行时条件不能是 alignment,因为原子会(过度)对齐内部存储以实现高效的无锁操作,而强制不对齐是 UB,可能表现为原子性的丧失。

The actual reason where runtime condition may determine atomicity is runtime CPU dispatch .运行时条件可能决定原子性的实际原因是运行时 CPU 调度

On x86-64, an implementation may detect the presence of cmpxchg16b via cpuid at initialization, and use it for 128-bit atomics, the same applies to cmpxchg8b and 64-bit atomic on 32-bit.在 x86-64 上,实现可以在初始化时通过cpuid检测cmpxchg16b的存在,并将其用于 128 位原子,这同样适用于cmpxchg8b和 32 位上的 64 位原子。 If corresponding cmpxchg is not found, lock-free atomic is unimplementable, and the implementation uses locks.如果没有找到对应的cmpxchg ,则 lock-free atomic 是无法实现的,并且该实现使用了锁。

MSVC doesn't do runtime CPU dispatch currently. MSVC 目前不执行运行时 CPU 调度。 It doesn't do it for 64-bit due to ABI compatibility reasons, and doesn't do it for 32-bit as already doesn't support CPUs without cmpxchg8b .由于 ABI 兼容性原因,它不会为 64 位执行此操作,并且不会为 32 位执行此操作,因为它已经不支持没有cmpxchg8b的 CPU。 Boost.Atomic doesn't do this by default (assumes cmpxchg8b and cmpxhg16b presence), but can be configured for the detection.默认情况下,Boost.Atomic 不执行此操作(假设cmpxchg8bcmpxhg16b存在),但可以配置用于检测。 I haven't bothered to look what other implementations do yet.我还没有费心去看看其他实现是做什么的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM