std :: atomic< bool>ARM(Raspberry Pi 3)上的无锁不一致 [英] std::atomic<bool> lock-free inconsistency on ARM (raspberry pi 3)

查看:88
本文介绍了std :: atomic< bool>ARM(Raspberry Pi 3)上的无锁不一致的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对静态断言有疑问.静态断言就是这样的:

I had a problem with a static assert. The static assert was exactly like this:

static_assert(std::atomic<bool>::is_always_lock_free);

并且在Raspberry Pi 3上代码失败(Linux raspberrypi 4.19.118-v7 +#1311 SMP Mon Apr 27 14:21:24 BST 2020 armv7l GNU/Linux).

and the code failed on Raspberry Pi 3 (Linux raspberrypi 4.19.118-v7+ #1311 SMP Mon Apr 27 14:21:24 BST 2020 armv7l GNU/Linux).

cppreference.com atomic :: is_always_lock_free参考网站上据说:

如果此原子类型始终是无锁的,则等于true;如果它从不或有时是无锁的,则等于false.该常量的值与宏ATOMIC_xxx_LOCK_FREE(定义的位置),成员函数is_lock_free和非成员函数std :: atomic_is_lock_free一致.

Equals true if this atomic type is always lock-free and false if it is never or sometimes lock-free. The value of this constant is consistent with both the macro ATOMIC_xxx_LOCK_FREE, where defined, with the member function is_lock_free and non-member function std::atomic_is_lock_free.

对我来说,第一个奇怪的事情是有时是无锁的".它取决于什么?但是稍后再问问题.

The first strange thing for me is "sometimes lock-free". What does it depend on? But questions later, back to the problem.

我做了一点测试.编写此代码:

I made a little test. Wrote this code:

#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;
}

编译并使用 g ++ -std = c ++ 17 atomic_test.cpp&&在树莓派上运行它./a.out(g++ 7.3.0和8.3.0,但这没关系)并得到:

compiled and ran it on raspberry using g++ -std=c++17 atomic_test.cpp && ./a.out (g++ 7.3.0 and 8.3.0, but that shouldn't matter) and got:

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

如您所见,它与cppreference网站上所说的不一致...为了进行比较,我在装有g ++ 7.5.0的笔记本电脑(Ubuntu 18.04.5)上运行了它,并得到了:

As you can see it is not as consistent as stated on the cppreference site... For comparison I ran it on my laptop (Ubuntu 18.04.5) with g++ 7.5.0 and got:

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

因此, ATOMIC_BOOL_LOCK_FREE 的值和 is_always_lock_free 常量的值有所不同.寻找 ATOMIC_BOOL_LOCK_FREE 的定义,我所能找到的是

So there is a difference in ATOMIC_BOOL_LOCK_FREE's value and of course the is_always_lock_free constant. Looking for the definition of ATOMIC_BOOL_LOCK_FREE all I could find is

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;

ATOMIC_BOOL_LOCK_FREE (或 __ GCC_ATOMIC_BOOL_LOCK_FREE )等于1或2有什么区别?如果是1,则它可能会或可能不会是无锁的;如果是2,则它是100%是无锁的?除0之外还有其他值吗?这是cppreference站点上的错误消息,指出所有这些返回值都应该一致吗?树莓派输出的哪个结果是真的?

What is the difference between ATOMIC_BOOL_LOCK_FREE (or __GCC_ATOMIC_BOOL_LOCK_FREE) being equal to 1 or 2? Is it a case where if 1 then it may or may not be lock-free and if 2 it is 100% lock-free? Are there any other values apart from 0? Is this an error on the cppreference site where it is stated that all those return values should be consistent? Which of the results for the raspberry pi output is really true?

推荐答案

1 表示有时无锁";在标准中.但这确实意味着在编译时不知道是无锁的" ".

1 means "sometimes lock free" in the standard. But really that means "not known to be lock free at compile time".

没有编译器选项,GCC的默认基准包括太旧的ARM芯片,以至于它们不支持原子RMW的必要指令,因此它必须编写可在古老CPU上运行的代码,始终调用libatomic函数而不是内联原子操作

Without compiler options, GCC's default baseline includes ARM chips so old that they don't support the necessary instructions for atomic RMWs, so it has to make code that could run on ancient CPUs, always calling libatomic functions instead of inlining atomic operations.

在具有ARMv7或ARMv8 CPU的RPi上运行运行时查询函数时,它会返回true.

The runtime query function returns true when you run it on an RPi with its ARMv7 or ARMv8 CPU.

使用 -march = native -mcpu = cortex-a53 ,您将得到 is_always_lock_free 为真,因为它是已知的在编译时,目标计算机肯定支持所需的指令.(这些选项告诉GCC制作可能无法在其他/较旧的CPU上运行的二进制文件.)这是

With -march=native or -mcpu=cortex-a53 you'd get is_always_lock_free being true, because it's known at compile time that the target machine definitely supports the required instructions. (Those options tell GCC to make a binary that might not run on other / older CPUs.) This was confirmed by the OP in comments.

没有该编译选项, std :: atomic 操作必须调用libatomic函数,因此即使在现代CPU上也有额外的开销.

Without that compile option, std::atomic operations have to call libatomic functions, so there's extra overhead even on a modern CPU.

GCC(和所有明智的编译器)实现 std :: atomic< T> 的方式,它对于所有实例都是无锁的,或者是无锁的,不检查对齐方式或在运行时针对每个对象执行的任何操作.

The way GCC (and all sane compilers) implement std::atomic<T>, it's either lock free for all instances or none, not checking alignment or whatever at runtime per object.

alignof(std :: atomic< int64_t>)仍为8,因此,如果

alignof(std :: atomic< int64_t>)仅为4,则它是未定义的行为您有未对齐的原子对象.(该UB的实际症状可能包括撕裂,即纯负载和纯存储的非原子性.)如果您遵循C ++规则,则所有原子对象都将对齐;只有将未对齐的指针投射到 atomic< int64_t>* 并尝试使用它.

alignof( std::atomic<int64_t> ) is 8 even if alignof( int64_t ) was only 4 on a 32-bit machine, so it's undefined behaviour if you have a misaligned atomic object. (The practical symptoms of that UB could include tearing, i.e. non-atomicity, for pure-load and pure-store.) If you follow C++ rules, all your atomic objects will be aligned; you'd only have a problem if you cast a misaligned pointer to atomic<int64_t> * and tried to use it.

这篇关于std :: atomic&lt; bool&gt;ARM(Raspberry Pi 3)上的无锁不一致的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆