确保与 std::hardware_constructive_interference_size 共享的正确方法

Cur*_*ous 5 c++ alignment c++17

确保在足够小以适合缓存行的结构中真正共享的正确且可移植的方法是什么?仅仅确保结构足够小就足够了吗?或者它也必须在缓存边界上对齐?

例如,假设缓存行的大小为 64 字节,以下是否足够?

struct A {
  std::uint32_t one;
  std::uint32_t two;
};
Run Code Online (Sandbox Code Playgroud)

还是我必须这样做?

struct alignas(std::hardware_constructive_interference_size) A {
  std::uint32_t one;
  std::uint32_t two;
};
Run Code Online (Sandbox Code Playgroud)

注意:这将始终在堆栈上,因此不需要过度对齐的内存分配。


另一个后续,这足以确保没有虚假共享吗?

struct A {
public:
  alignas(hardware_destructive_interference_size) std::uint32_t one;
  alignas(hardware_constructive_interference_size) std::uint32_t two;
};
Run Code Online (Sandbox Code Playgroud)

还是必须这样做(在说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;
};
Run Code Online (Sandbox Code Playgroud)

Joh*_*ann 5

第二种变体是目前你能做的最好的。

但是,没有 100% 可移植的方式来对齐缓存行大小。常量hardware_constructive_interference_sizehardware_destructive_interference_size只是提示。它们是编译器的最佳猜测。最终,您在编译时不知道 L1 缓存行大小。

但在实践中,这通常无关紧要,因为对于大多数架构来说,都有一个典型的缓存行大小,例如 x86 为 64 字节。

更重要的是,对于像您的示例中的小结构,自然对齐结构以确保它完全在缓存行内总是足够的。在您的具体示例中,这意味着

struct alignas(8) A {
  std::uint32_t one;
  std::uint32_t two;
};
Run Code Online (Sandbox Code Playgroud)

将始终确保真正的共享,无论运行时的实际 L1 缓存线大小如何,只要缓存线大小为 8 字节或更大。(如果它更小,您将永远不会真正实现真正的共享。)

关于后续问题:第二个变体将确保没有错误共享。第一个变体可能会导致错误共享,因为缓存行大小可能确实如此,hardware_destructive_interference_size在这种情况下,您将进行错误共享(假设hardware_constructive_interference_size< hardware_destructive_interference_size)。

但在实践中hardware_destructive_interference_sizehardware_constructive_interference_size对于大多数架构将具有相同的值。这有点过度设计,因为这两个常量都不能为您提供真正的 L1 缓存行大小,而只是一个编译时的猜测。