gpt4 book ai didi

c++ - g++/gcc 是否支持 C++20 新的atomic_flag 功能?

转载 作者:行者123 更新时间:2023-12-02 02:31:55 30 4
gpt4 key购买 nike

根据cppreference ,c++20 对 atomic_flag 操作有丰富的(对我来说很有用的)支持。

但是,尚不清楚 gcc 是否支持这些功能,在 gnu's feature summary 上找不到它们。 。我目前使用的是版本 8,并设置了 -c++=2a

此代码无法使用 GCC8 编译:

#include <atomic>

int main() {
std::atomic_flag myFlag = ATOMIC_FLAG_INIT;
myFlag.test();
}

错误:“struct std::atomic_flag”没有名为“test”的成员

我不想通过安装较新版本的 g++ 来破坏我的构建环境的稳定性,并且非常感谢任何能够报告版本 10 或更高版本中对 atomic_flag 支持的人。

最佳答案

atomic<bool> 执行 atomic_flag 执行的所有操作,就像在所有普通 C++ 实现上一样高效。 C++20 刚刚向atomic_flag 添加了新内容,使其达到 atomic<bool> 的级别。 atomic_flag 保证是无锁的,但实际上在所有平台上任何人都关心,atomic<bool> 也是如此。

不要指望 GCC8 拥有所有 C++2a 功能;至少在最新版本或 nightly gcc 的 https://godbolt.org/ 上尝试一下。 (另请注意,需要支持这一点的不是编译器本身,而是标准库 header 。但 libstdc++ 通常与 g++ 一起分发。)

我调整了您的示例,以便可以在启用优化的情况下对其进行编译,而无需优化实际工作。

#include <atomic>

int flagtest(std::atomic_flag &myFlag) {
//std::atomic_flag myFlag = ATOMIC_FLAG_INIT;
return myFlag.test();
}

On the Godbolt compiler explorer 与 gcc 和 clang:GCC10.2 不支持新的 C++20 atomic_flag::test() 成员函数,GCC nightly trunk build 支持。 Clang 11.0 和 trunk 可以,而 clang 10.0.1 则不行。

# GCC trunk for x86-64 -O3 -std=gnu++2a
flagtest(std::atomic_flag&):
movzx eax, BYTE PTR [rdi]
ret
booltest(std::atomic<bool>&):
movzx eax, BYTE PTR [rdi]
test al, al
setne al
movzx eax, al # this is weird, GCC has gone insane.
ret

借助 clang,我们还可以尝试 libc++(C++ 标准库的新实现)。默认情况下,Linux(包括 Godbolt)上的 clang 使用 libstdc++,就像 GCC 一样。

# clang 11.0 -O3 -std=gnu++2a -stdlib=libc++
flagtest(std::__1::atomic_flag&):
mov al, byte ptr [rdi]
movzx eax, al
and eax, 1
ret
booltest(std::__1::atomic<bool>&):
mov al, byte ptr [rdi]
movzx eax, al
and eax, 1
ret

所以这很奇怪也很可怕;即使内存中的值可能没有被 bool 化,也没有理由将字节 movthen movzx eax,al 合并到 RAX 的低字节中。首先加载 movzx 即可! (Clang 确实有鲁莽的倾向 with x86 false dependencies in general ,但通常它至少可以通过使用 mov 而不是 movzx 来节省一个字节,如果不是整个异或清零指令的话。但这里它是一个额外的指令。 )

但是,如果 and eax,1 认为需要重新 bool 化,那么它比 GCC 的疯狂 test/setnz/movzx 要好得多。 (实际上不需要这样做;ABI 保证内存中的 bool 是实际的 01 字节,并且 atomic<bool> 使用与 bool 相同的对象表示形式。)

因此,使用 clang 时,这两种方式都有愚蠢的错过优化转换为 int 。由于某种原因,使用 GCC atomic_flag 不会遇到这个问题,但我不建议仅仅因为这个原因使用它。希望 atomic<bool> 能够得到修复,并且通常您不会将 bool 转换为 int。


正常使用 atomic<bool>atomic_flag ,例如在其上分支,不应该有任何这些错过的优化。例如

int g0, g1;
int conditional_load(std::atomic<bool> &myFlag) {
return myFlag ? g0 : g1;
}
# gcc 11 nightly build -O3
conditional_load(std::atomic<bool>&):
movzx eax, BYTE PTR [rdi]
test al, al
mov eax, DWORD PTR g0[rip]
cmove eax, DWORD PTR g1[rip]
ret

所以这很正常。 Clang 选择在地址之间进行选择,然后加载一次。这将加载使用延迟置于关键路径上并需要更多指令;当两个变量相邻时,这是更糟糕的选择,因此可能来自同一缓存行。 (GCC 的选择总是涉及两个变量,如果一个变量可以在缓存中保持“冷”状态,情况可能会更糟)。

关于c++ - g++/gcc 是否支持 C++20 新的atomic_flag 功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64914827/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com