繁体   English   中英

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

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

谁能告诉我 std::atomic::is_lock_free() 不是 static 和 constexpr 吗? 让它非静态和/或非 constexpr 对我来说没有意义。

cppreference中所述:

除了 std::atomic_flag 之外的所有原子类型都可以使用互斥锁或其他锁定操作来实现,而不是使用无锁原子 CPU 指令。 原子类型有时也可以是无锁的,例如,如果仅对齐的 memory 访问在给定架构上自然是原子的,则相同类型的未对齐对象必须使用锁。

C++ 标准建议(但不要求)无锁原子操作也是无地址的,即适用于使用共享 memory 的进程之间的通信。

正如其他人所提到的, std::is_always_lock_free可能是您真正想要的。


编辑:澄清一下,C++ object 类型具有 alignment 值,该值将其实例的地址限制为仅是 2 的某些幂的倍数( [basic.align] )。 这些 alignment 值是针对基本类型的实现定义的,不需要等于类型的大小。 它们也可能比硬件实际支持的更严格。

例如,x86(大部分)支持非对齐访问。 但是,您会发现大多数编译器对于 x86 具有alignof(double) == sizeof(double) == 8 ,因为未对齐的访问有许多缺点(速度、缓存、原子性......)。 但是例如#pragma pack(1) struct X { char a; double b; }; #pragma pack(1) struct X { char a; double b; }; alignas(1) double x; 允许您拥有“未对齐”的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).

这里有更多信息: 成功的非对齐访问对 x86 的实际影响是什么?

还请查看下面@Peter Cordes的富有洞察力的评论!

您可以使用std::is_always_lock_free

is_lock_free取决于实际系统,无法在编译时确定。

相关解释:

原子类型有时也可以是无锁的,例如,如果仅对齐的 memory 访问在给定架构上自然是原子的,则相同类型的未对齐对象必须使用锁。

我已经在我的 Windows-PC 上安装了 Visual Studio 2019,这个 devenv 也有一个 ARMv8 编译器。 ARMv8 允许非对齐访问,但比较和交换、锁定添加等都必须对齐。 而且,使用ldpstp (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>都正确对齐。 这避免了运行时 alignment 检查每次加载和存储的需要。

(编者注:这很常见;大多数现实生活中的 C++ 实现都是这样工作的。这就是std::is_always_lock_free如此有用的原因:因为它通常适用于is_lock_free()永远为真的类型。)

std::atomic<T>::is_lock_free()在某些实现中可能会根据运行时条件返回truefalse

正如 Peter Cordes 在评论中指出的那样,运行时条件不能是 alignment,因为原子会(过度)对齐内部存储以实现高效的无锁操作,而强制不对齐是 UB,可能表现为原子性的丧失。

运行时条件可能决定原子性的实际原因是运行时 CPU 调度

在 x86-64 上,实现可以在初始化时通过cpuid检测cmpxchg16b的存在,并将其用于 128 位原子,这同样适用于cmpxchg8b和 32 位上的 64 位原子。 如果没有找到对应的cmpxchg ,则 lock-free atomic 是无法实现的,并且该实现使用了锁。

MSVC 目前不执行运行时 CPU 调度。 由于 ABI 兼容性原因,它不会为 64 位执行此操作,并且不会为 32 位执行此操作,因为它已经不支持没有cmpxchg8b的 CPU。 默认情况下,Boost.Atomic 不执行此操作(假设cmpxchg8bcmpxhg16b存在),但可以配置用于检测。 我还没有费心去看看其他实现是做什么的。

暂无
暂无

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

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