受保护成员变量的虚假共享?

5
考虑:
class Vector
{
  double x, y, z;
  // …
};

class Object
{
  Vector Vec1, Vec2;
  std::mutex Mtx1, Mtx2;

  void ModifyVec1() { std::lock_guard Lock(Mtx1); /* … */ }
  void ModifyVec2() { std::lock_guard Lock(Mtx2); /* … */ }
};

如果互斥锁或保护变量在缓存时共享同一缓存行,是否会导致某种形式的“交叉锁定”?如果是这样,将互斥锁声明在它们保护的变量右侧(或左侧)是否是一个好习惯?将类对齐到std::hardware_destructive_interference_sizeP0154)可能会避免此效果。潜在的好处是否值得超过对象的超对齐?

C++标准不要求类成员按任何特定顺序排列(有一些不适用于此处的警告)。您可以从编译器的文档中确定它是否对类成员使用确定性顺序(很可能是这样)。 - Sam Varshavchik
3
对于标准布局类,它们必须按照声明顺序排列。根据目前公布的内容,这可能是一个标准布局类。由于OP正在询问特定实现的细节,因此这并不重要。 - M.M
@Rakete1111 请随意编辑 - metalfox
@metalfox 等等,什么?我只是在“回答”你的第一个问题 :) 我不会将它们放在变量上面的特定顺序中,而是会给它们命名,以便清楚地表明互斥锁保护了特定的变量。 - Rakete1111
@Barry 我只是在尝试弄清它们的用处。 - metalfox
显示剩余4条评论
1个回答

4

根据您提供的问题,您的变量似乎没有关联,因此您可能需要使用 hardware_constructive_interference_size 而不是 hardware_destructive_interference_size

struct keep_together {
    std::mutex m;
    Vector v;
};

alignas(std::hardware_constructive_interference_size) keep_together k1;
alignas(std::hardware_constructive_interference_size) keep_together k2;

destructive用于像无锁队列这样的情况,当线程正在读取两个不同的atomic并且您想确保它们都被实际加载时。如果这是一个问题,您需要解释为什么要避免伪共享。

在变量之后(或之前)声明互斥锁以增加它们在同一高速缓存行上的机会是否是一种好的做法?

那就是constructive干涉。


感谢澄清。我混淆了两个概念。我想鼓励真正的共享,但也想防止假共享的发生。假设互斥锁是连续存储的。它们可能共享缓存行吗?我编辑了问题,希望更清晰明了。 - metalfox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接