什么是正确的和可移植的方式,以确保真正的共享在一个足够小的结构,适合在一个背书?仅仅确保结构足够小就足够了吗?还是也必须在缓存边界上对齐?
例如,假设一条直线的大小为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;
};发布于 2019-02-03 01:57:41
第二个变体是目前你能做的最好的。
但是,没有100%的可移植方式来对齐缓存行大小。常量hardware_constructive_interference_size和hardware_destructive_interference_size只是提示。它们是编译器的最佳猜测。最终,您不知道编译时的L1缓存行大小。
但在实践中,这通常并不重要,因为对于大多数体系结构来说,有一个典型的缓存行大小,比如x86的64字节。
更重要的是,对于类似于您的示例中的小型结构,只需自然地对齐结构以确保其完全位于缓存行内就足够了。在您的具体示例中,这意味着
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缓存行大小,而只是编译时猜测,这在一定程度上是过度设计的。
https://stackoverflow.com/questions/54499146
复制相似问题