簡體   English   中英

為什么標准庫不以無鎖方式為8字節以下的結構實現std :: atomic?

[英]Why don't standard libraries implement std::atomic for structs under 8 bytes in a lock-free manner?

假設該體系結構可以為std :: atomic以無鎖方式支持8字節標量。 為什么標准庫不為8字節以下的結構提供類似的特化?

這種std :: atomic特化的簡單實現只能將結構序列化/反序列化(使用std::memcpy )到等效的std::uintx_t ,其中x是結構的寬度(以位為單位)(舍入為最接近的冪) 2大於或等於結構的寬度)。 這將被很好地定義,因為std :: atomic需要這些結構是可以輕易復制的。

例如。 https://godbolt.org/z/sxSeId ,這里Something只有3個字節,但實現調用__atomic_load__atomic_exchange ,兩者都使用鎖表。

使用struct Something { alignas(4) char a; char b,c; }; struct Something { alignas(4) char a; char b,c; }; (不是alignas(4) char a,b,c;因為這會使每個 char填充為4個字節,因此它們可以各自對齊。)

具有非2次冪大小的對象可能跨越高速緩存行邊界,因此使用更寬的4字節負載並不總是可行的。

加上純商店總是必須使用CAS(例如lock cmpxchg )來避免發明寫入對象外的字節:顯然你不能使用兩個單獨的mov存儲(2字節+ 1字節),因為這不會是原子的,除非你在帶有重試循環的TSX事務中這樣做。


對於不跨越8字節邊界的內存訪問,x86加載/存儲僅保證原子性。 (在一些供應商/搜索中,緩存行邊界。或者對於可能不可緩存的加載/存儲,基本上自然對齊是您需要的)。 為什么在x86上對自然對齊的變量進行整數賦值?

你的struct Something { char a, b, c; }; struct Something { char a, b, c; }; 沒有對齊要求所以沒有C ++規則阻止Something對象跨越2個緩存行。 這將使個純mov它加載/存儲絕對非原子。

gcc和鐺選擇實現atomic<T>用相同的布局/對象的表示為T (無論是無鎖的或沒有)。 因此, atomic<Something>是一個3字節的對象。 因此, atomic<Something>的數組必然會有一些跨越緩存行邊界的對象,並且不能在對象外部填充,因為這不是數組在C中的工作方式sizeof() = 3告訴您數組布局。 這使得無鎖atomic<Something>變得不可能。 (除非你使用lock cmpxchg加載/存儲即使在緩存行拆分時也是原子的,否則會在發生這種情況時產生巨大的性能損失。更好地讓開發人員修復它們的結構。)

atomic<T>類可以具有比T更高的對齊要求,例如atomic<int64_t>具有alignof(atomic_int64_t)== 8,與許多32位平台(包括i386 System V alignof(int64_t) == 4上的alignof(int64_t) == 4不同ABI)。

如果gcc / clang沒有選擇保持布局相同,那么他們可能有atomic<T>墊小對象,直到2的下一個冪並添加對齊,這樣它們就可以無鎖。 這將是一個有效的實現選擇。 我想不出任何缺點。


有趣的是,gcc的C11 _Atomic支持在具有64位無鎖原子的32位平台上略有破壞_Atomic _Atomic int64_t可能在結構內部未對齊導致撕裂。 他們仍然沒有更新_Atomic類型的ABI以具有自然對齊。

但是g ++的C ++ 11 std :: atomic在一個標題中使用了一個模板類來修復那個bug( https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65147 ); 確保atomic<T>具有自然對齊(最大為2個大小的冪),即使T具有對齊<大小。 因此,他們無法跨越任何邊界。

暫無
暫無

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

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