C++11:16 字节 atomic<> 变量是否在允许 CMPXCHG16B 指令的 16 字节边界上自动对齐?
C++11: are 16-byte atomic<> variables automatically aligned on 16-byte boundaries allowing CMPXCHG16B instruction?
16 字节 atomic<>
变量是否在 16 字节边界上自动对齐,从而允许 compiler/runtime 库有效地使用 x86 CMPXCHG16B
指令?还是我们应该始终为所有此类变量手动指定 alignas(16)
?
如果库使用 lock cmpxchg16b
而不是 16 字节的互斥量,std::atomic<>
的任何体面的实现都将使用 alignas
本身来提高 lock cmpxchg16b
的效率对象。
并非所有实现都如此,例如,我认为 MSVC 的标准库使用标准互斥回退使 16 字节对象完全无锁。
您不需要 alignas(16)
atomic<T>
。
如果您有一个要在其上使用 atomic_ref
的普通 T
对象,则只需要手动对齐原子。 atomic_ref<>
没有对齐现有 T 对象的机制。当前版本的设计公开了一个您应该使用的 required_alignment
成员。为了正确性,由你来做。 (否则你会得到 UB,这可能意味着撕裂,或者 极度 拆分 lock
RMW 的系统范围性能缓慢。)
// for atomic_ref<T>
alignas(std::atomic_ref<T>::required_alignment) T sometimes_atomic_var;
// often equivalent, and doesn't require checking that atomic_ref<T> is supported
alignas(std::atomic<T>) T sometimes_atomic_var;
// use the same alignment as atomic<T>
请注意,跨高速缓存行边界的未对齐 lock cmpxchg16b
拆分仍然是原子的,但非常非常慢(与任何 lock
ed 指令相同:原子 RMW 的原子性保证不取决于结盟)。更像是一个实际的总线锁,而不仅仅是一个本地到这个核心 .
更窄的原子肯定需要自然对齐以确保正确性,因为纯加载和纯存储可以编译为 。
但是 16 字节的对象只有 lock cmpxchg16b
保证是原子的,所以 .load()
和 .store()
必须用 lock cmpxchg16b
来实现。 (加载 CAS(0,0) 以获取旧值,然后将 0 替换为自身或什么都不做,然后使用 CAS 重试循环进行存储。这很糟糕,但比互斥锁要好一些。它没有读取 -您期望从无锁 load
获得的侧面可伸缩性,这是 GCC7 和后来不再将 atomic<16-byte-object>
宣传为无锁的原因之一,即使它仍将使用 lock cmpxchg16b
它调用的 libatomic 函数而不是内联 lock cmpxchg16b
)
16 字节 atomic<>
变量是否在 16 字节边界上自动对齐,从而允许 compiler/runtime 库有效地使用 x86 CMPXCHG16B
指令?还是我们应该始终为所有此类变量手动指定 alignas(16)
?
如果库使用 lock cmpxchg16b
而不是 16 字节的互斥量,std::atomic<>
的任何体面的实现都将使用 alignas
本身来提高 lock cmpxchg16b
的效率对象。
并非所有实现都如此,例如,我认为 MSVC 的标准库使用标准互斥回退使 16 字节对象完全无锁。
您不需要 alignas(16)
atomic<T>
。
如果您有一个要在其上使用 atomic_ref
的普通 T
对象,则只需要手动对齐原子。 atomic_ref<>
没有对齐现有 T 对象的机制。当前版本的设计公开了一个您应该使用的 required_alignment
成员。为了正确性,由你来做。 (否则你会得到 UB,这可能意味着撕裂,或者 极度 拆分 lock
RMW 的系统范围性能缓慢。)
// for atomic_ref<T>
alignas(std::atomic_ref<T>::required_alignment) T sometimes_atomic_var;
// often equivalent, and doesn't require checking that atomic_ref<T> is supported
alignas(std::atomic<T>) T sometimes_atomic_var;
// use the same alignment as atomic<T>
请注意,跨高速缓存行边界的未对齐 lock cmpxchg16b
拆分仍然是原子的,但非常非常慢(与任何 lock
ed 指令相同:原子 RMW 的原子性保证不取决于结盟)。更像是一个实际的总线锁,而不仅仅是一个本地到这个核心
更窄的原子肯定需要自然对齐以确保正确性,因为纯加载和纯存储可以编译为
但是 16 字节的对象只有 lock cmpxchg16b
保证是原子的,所以 .load()
和 .store()
必须用 lock cmpxchg16b
来实现。 (加载 CAS(0,0) 以获取旧值,然后将 0 替换为自身或什么都不做,然后使用 CAS 重试循环进行存储。这很糟糕,但比互斥锁要好一些。它没有读取 -您期望从无锁 load
获得的侧面可伸缩性,这是 GCC7 和后来不再将 atomic<16-byte-object>
宣传为无锁的原因之一,即使它仍将使用 lock cmpxchg16b
它调用的 libatomic 函数而不是内联 lock cmpxchg16b
)