簡體   English   中英

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

[英]Are C++20 new atomic_flag features supported in g++ / gcc?

根據cppreference ,c++20 對atomic_flag操作有豐富的(並且對我有用的)支持。

但是,不清楚 gcc 是否支持這些功能,在gnu 的功能摘要中找不到它們。 我目前使用的是版本 8,設置了-c++=2a

這段代碼不能用 GCC8 編譯:

#include <atomic>

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

error: 'struct std::atomic_flag' has no member named 'test'

我不想通過安裝較新版本的 g++ 來破壞我的構建環境,如果有人能報告版本 10 或更高版本對atomic_flag的支持,我將不勝感激。

atomic<bool>完成atomic_flag所做的一切,就像在所有普通 C++ 實現上一樣有效。 C++20 剛剛向 atomic_flag 添加了新內容,以將其提升到atomic<bool>的級別。 atomic_flag保證是 lock_free 的,但實際上在任何人關心的所有平台上, atomic<bool>也是如此。

不要期望 GCC8 擁有所有 C++2a 特性; 至少在https://godbolt.org/上試用最新版本或每晚 gcc。 (另請注意,需要支持的不是適當的編譯器,只是標准庫頭文件。但 libstdc++ 通常與 g++ 一起分發。)

我調整了您的示例,以便可以在啟用優化的情況下對其進行編譯,而無需優化實際工作。

#include <atomic>

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

在帶有 gcc 和 clang 的 Godbolt 編譯器資源管理器上: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 上的 clang(包括 Godbolt)使用 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

所以這很奇怪也很可怕。 即使內存中的值可能沒有被布爾化,也沒有理由將字節mov然后movzx eax,al合並到 RAX 的低字節中。 首先做一個movzx加載! (Clang 確實傾向於對x86 錯誤依賴項魯莽行事,但通常它至少可以通過使用mov而不是movzx來節省一個字節,如果不是整個異或歸零指令的話。但這里需要額外的指令。)

但是,如果它認為需要重新布爾化,那么and eax,1比 GCC 的 insane 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 選擇在地址之間進行選擇,然后加載一次。 這將負載使用延遲置於關鍵路徑上並需要更多指令; 當兩個 var 相鄰時,選擇更糟糕,因此可能來自同一緩存行。 (GCC 的選擇總是涉及兩個 var,如果一個可以在緩存中保持“冷”狀態可能會更糟)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM