繁体   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