什么是确保在结构足够小,适合在高速缓存行真正共享的正确和可移植的方法?它是不够的,只是确保结构足够小?或者它也有高速缓存边界上对齐?
例如,假定一个高速缓存行的大小为64个字节,是以下足够?
struct A {
std::uint32_t one;
std::uint32_t two;
};
还是我必须这样做?
struct alignas(std::hardware_constructive_interference_size) A {
std::uint32_t one;
std::uint32_t two;
};
注意:这将永远是在栈上,所以没有过度对齐的存储空间的分配应符合规定。
另一个随访,这是足以保证共享假没有?
struct A {
public:
alignas(hardware_destructive_interference_size) std::uint32_t one;
alignas(hardware_constructive_interference_size) std::uint32_t two;
};
或者没有一个不得不这样做(在说hardware_constructive_interference_size
<hardware_destructive_interference_size
的情况?)
struct A {
public:
alignas(hardware_destructive_interference_size) std::uint32_t one;
alignas(hardware_destructive_interference_size) std::uint32_t two;
};
目前第二个变量是你能做的最好的。
然而,没有对齐到高速缓存行大小的100%可移植的方式。常量hardware_constructive_interference_size
和hardware_destructive_interference_size
只是暗示。他们是编译器的最佳猜测。最终,你不知道在编译时的L1高速缓存行的大小。
但在实践中,这通常并不重要,因为对于大多数的架构有一个典型的高速缓存行的大小,如64个字节用于x86。
更有甚者,在你的例子小结构一样,它始终是足够的自然对齐结构,以确保它完全是一个高速缓存行内。在您的具体的例子,这意味着
struct alignas(8) A {
std::uint32_t one;
std::uint32_t two;
};
将始终确保真正共享,而不管在运行时实际L1高速缓存行大小的,条件是该高速缓存行大小为8个字节或更大。 (如果是较小的,你将永远不会有真正的共享平凡。)
关于后续问题:第二个变量将确保共享假没有。第一个变种可能导致错误共享的高速缓存行大小可能真的hardware_destructive_interference_size
在这种情况下,你将有共享假的(在假设hardware_constructive_interference_size
<hardware_destructive_interference_size
)。
但在实践中hardware_destructive_interference_size
和hardware_constructive_interference_size
会对大多数架构相同的值。这有点过度设计,因为没有恒定为您提供真正的L1高速缓存行的大小,但只是一个编译时的猜测。