是否可以有一个从释放存储操作到不同线程中的存储的释放序列?

2024-01-11

我知道线程 2 中的释放存储操作和线程 1 中的获取加载操作之间会出现同步关系,即使该加载操作不直接读取线程 2 存储的值,前提是有一个释放存储操作和实际读取的存储之间的“释放顺序”只要:

  1. 实际读取的存储与释放存储操作位于同一线程中。
  2. 在修改顺序中,释放存储操作和实际读取的存储之间的其他线程中没有存储(但允许读取-修改-写入操作)。

但是,我不明白为什么当实际读取的存储位于不同的线程中时不可能进行同步,前提是释放存储操作仍然发生在正在读取的存储之前。实际上正在被阅读。标准明确不允许这样做吗?如果是这样,那么该标准是否可能不完整,因为它有意义并且所有现有硬件无论如何都会有这样的同步?

考虑以下示例,其中 a、x 和 y 是用 0 初始化的原子 int。

主题 1:

k = y.load(memory_order_acquire);
x.store(1, memory_order_relaxed);

话题2:

m = x.load(memory_order_relaxed);
y.store(2, memory_order_release);
a.store(2, memory_order_release);

主题 3:

n = a.load(memory_order_acquire);
y.store(3, memory_order_relaxed);

问题是,我们最终有可能得到 k = 3、m = 1 和 n = 2 吗?

如果线程 2 中对 y 的存储与线程 3 中对 y 的存储之间不存在释放序列,则线程 2 中对 y 的释放存储与线程 1 中对 y 的获取读取之间不存在同步,因此线程 2 中 x 的加载不必发生在线程 1 中存储到 x 之前,从而使 k、m 和 n 的所需结果成为可能。

但是,如果有is线程 2 中 y 的存储和线程 3 中 y 的存储之间的释放序列isa 在线程 2 中对 y 的释放存储与线程 1 中对 y 的获取读取之间进行同步,因此线程 2 中 x 的加载需要在线程 1 中对 x 的存储之前发生,从而获得 k 的所需结果、m 和 n 不可能。请注意,如果 a 的存储/加载不存在,并且我们只是在线程 2 结束时将值 3 宽松地存储到 y,那么就会出现这种情况(因此永远不会发生 k=3 和 m= 1).

在这种情况下,值 3 到 y 的存储发生在线程 3 中,但是使用原子变量 a 进行释放-获取同步;因此,如果 n=2,则值 2 到 y 的释放存储与值 3 到 y 的宽松存储之间存在先发生关系。那是不是意味着有isk=3、m=1 和 n=2 的释放序列和结果永远不会发生?

Edit

请注意,运行以下代码片段:

int main()
{
  atomic_int a = 0;
  atomic_int x = 0;
  atomic_int y = 0;

  {{{
    {
      y.load(memory_order_acquire).readsvalue(3);
      x.store(1, memory_order_relaxed);
    }
  |||
    {
      x.load(memory_order_relaxed).readsvalue(1);
      y.store(2, memory_order_release);
      a.store(2, memory_order_release);
    }
  |||
    {
      a.load(memory_order_acquire).readsvalue(2);
      y.store(3, memory_order_relaxed);
    }
  }}}
}

on http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/ http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/导致 1 一致执行:

原因是从节点 g 到节点 j 没有 rs 边(因此从 j 到 d 没有 sw/hb 边)。

相比之下,当我们将宽松写入简单地放在线程 2 的末尾时:

int main()
{
  atomic_int a = 0;
  atomic_int x = 0;
  atomic_int y = 0;

  {{{
    {
      y.load(memory_order_acquire).readsvalue(3);
      x.store(1, memory_order_relaxed);
    }
  |||
    {
      x.load(memory_order_relaxed).readsvalue(1);
      y.store(2, memory_order_release);
      y.store(3, memory_order_relaxed);
    }
  }}}
}

那么就没有一致的执行,即:

通过让节点 f 从节点 e 读取而 f 发生在节点 e 之前来打破因果关系。这里的主要区别在于,现在有一条从节点 g 到 h 的“rs”边,这会导致从节点 g 到节点 d 的同步(sw)边,因此在相同节点之间会出现一条发生在(hb)边。


None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否可以有一个从释放存储操作到不同线程中的存储的释放序列? 的相关文章

随机推荐