Rog*_*gus 6 c++ gcc arm raspberry-pi stdatomic
我的静态断言有问题。静态断言完全是这样的:
static_assert(std::atomic<bool>::is_always_lock_free);
Run Code Online (Sandbox Code Playgroud)
并且代码在 Raspberry Pi 3 上失败(Linux raspberrypi 4.19.118-v7+ #1311 SMP Mon Apr 27 14:21:24 BST 2020 armv7l GNU/Linux)。
在cppreference.comatomic::is_always_lock_free 参考站点上指出:
如果此原子类型始终是无锁的,则等于 true;如果它从不或有时是无锁的,则等于 false。该常量的值与定义的宏 ATOMIC_xxx_LOCK_FREE、成员函数 is_lock_free 和非成员函数 std::atomic_is_lock_free 一致。
对我来说第一个奇怪的事情是“有时无锁”。它取决于什么?但问题过后,回到问题。
我做了一个小测试。写了这段代码:
#include <iostream>
#include <atomic>
int main()
{
std::atomic<bool> dummy {};
std::cout << std::boolalpha
<< "ATOMIC_BOOL_LOCK_FREE --> " << ATOMIC_BOOL_LOCK_FREE << std::endl
<< "dummy.is_lock_free() --> " << dummy.is_lock_free() << std::endl
<< "std::atomic_is_lock_free(&dummy) --> " << std::atomic_is_lock_free(&dummy) << std::endl
<< "std::atomic<bool>::is_always_lock_free --> " << std::atomic<bool>::is_always_lock_free << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
g++ -std=c++17 atomic_test.cpp && ./a.out使用(g++ 7.3.0和8.3.0,但这不重要)在树莓派上编译并运行它并得到:
ATOMIC_BOOL_LOCK_FREE --> 1
dummy.is_lock_free() --> true
std::atomic_is_lock_free(&dummy) --> true
std::atomic<bool>::is_always_lock_free --> false
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它与 cppreference 网站上所述的不一致...为了进行比较,我在我的笔记本电脑(Ubuntu 18.04.5)上使用 g++ 7.5.0 运行它并得到:
ATOMIC_BOOL_LOCK_FREE --> 2
dummy.is_lock_free() --> true
std::atomic_is_lock_free(&dummy) --> true
std::atomic<bool>::is_always_lock_free --> true
Run Code Online (Sandbox Code Playgroud)
ATOMIC_BOOL_LOCK_FREE所以的值和常数当然是有区别的is_always_lock_free。ATOMIC_BOOL_LOCK_FREE寻找我能找到的所有定义是
c++/8/bits/atomic_lockfree_defines.h: #define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
c++/8/atomic: static constexpr bool is_always_lock_free = ATOMIC_BOOL_LOCK_FREE == 2;
Run Code Online (Sandbox Code Playgroud)
ATOMIC_BOOL_LOCK_FREE(或__GCC_ATOMIC_BOOL_LOCK_FREE) 等于 1 或 2有什么区别?是否存在这样的情况:如果是 1 那么它可能是无锁的,也可能不是无锁的,如果是 2 则它是 100% 无锁的?除了0还有其他值吗?这是 cppreference 网站上的一个错误,其中指出所有这些返回值应该一致吗?树莓派输出的哪个结果是真实的?
宏ATOMIC_xxx_LOCK_FREE的意思是:
0\xe2\x80\x8b对于永远不会无锁的内置原子类型1对于有时是无锁的内置原子类型2对于始终无锁的内置原子类型。因此,在您的 PI 环境中,astd::atomic<bool>有时是无锁的,并且dummy您正在测试的实例是无锁的 - 这意味着所有实例都是无锁的。
bool std::atomic_is_lock_free( const std::atomic<T>* obj ):
\n\n在任何给定的程序执行中,对于相同类型的所有指针,无锁查询的结果都是相同的。
\n
唯一的缺点是,在运行程序之前,您不知道该类型是否是无锁的。
\nIf(not std::atomic_is_lock_free(&dummy)) {\n std::cout << "Sorry, the program will be slower than expected\\n";\n}\nRun Code Online (Sandbox Code Playgroud)\n
1在标准中表示“有时无锁”。 但实际上这意味着“在编译时不知道是否是无锁的”。
如果没有编译器选项,GCC 的默认基线包括非常旧的 ARM 芯片,以至于它们不支持原子 RMW 的必要指令,因此它必须编写可以在古老的 CPU 上运行的代码,始终调用 libatomic 函数而不是内联原子操作。
当您在具有 ARMv7 或 ARMv8 CPU 的 RPi 上运行时,运行时查询函数将返回 true。
有了-march=nativeor-mcpu=cortex-a53你就会得到真实的,因为在编译时is_always_lock_free就知道目标机器肯定支持所需的指令。(这些选项告诉 GCC 制作一个可能无法在其他/较旧的 CPU 上运行的二进制文件。)OP 在注释中证实了这一点。
如果没有该编译选项,std::atomic操作必须调用 libatomic 函数,因此即使在现代 CPU 上也会产生额外的开销。
GCC(和所有理智的编译器)实现的方式std::atomic<T>,它要么对所有实例都是无锁的,要么没有锁,不检查对齐或在运行时每个对象的任何内容。
alignof( std::atomic<int64_t> )是 8,即使alignof( int64_t )在 32 位机器上只有 4,所以如果你有一个未对齐的原子对象,这是未定义的行为。(该 UB 的实际症状可能包括纯加载和纯存储的撕裂,即非原子性。)如果遵循 C++ 规则,所有原子对象都将对齐;atomic<int64_t> *如果您将一个未对齐的指针投射到并尝试使用它,那么您只会遇到问题。
| 归档时间: |
|
| 查看次数: |
1443 次 |
| 最近记录: |