是否可以从发布存储操作到另一个线程中的存储具有发布序列?

时间:2018-01-17 01:22:20

标签: c++ multithreading c++11 concurrency

我知道线程2中的发布存储操作和线程1中的获取加载操作之间会发生同步关系,即使该加载操作不直接读取线程存储的值2,只要有一个"释放顺序"在发布商店操作和实际读取的商店之间只要:

  1. 实际读取的存储与发布存储操作位于同一个线程中。
  2. 在修改顺序中,在发布存储操作和实际正在读取的存储之间的其他线程中没有存储(尽管允许读取 - 修改 - 写入操作)。
  3. 但是,如果发布存储操作仍然存在,那么当实际读取的存储位于不同的线程中时,我没有看到任何原因导致无法进行同步的原因。发生在实际读取的商店之前。标准明确不允许这样做吗?如果是这样,那么标准是否有可能是不完整的,因为它是有意义的,所有现有硬件无论如何都会有这样的同步?

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

    主题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之间没有同步 - 并且在线程中获取y的读取因此,线程2中的x的负载不必在线程1中存储到x之前发生,从而使得k,m和n的期望结果成为可能。

    但是,如果在线程2中存储到y​​和线程3中存储到y​​之间的释放序列那么之间的同步 - 在线程2中释放存储到y并且在线程1中读取y,因此线程2中的x的加载需要发生 - 在线程1中存储到x之前,使得k,m和n的期望结果不可能。请注意,如果那里没有存储/加载,我们只是在线程2的末尾做了值为3到y的松弛存储,那么情况就是如此(所以k = 3并不会发生M = 1)。

    在这种情况下,值3到y的存储发生在线程3中,但是存在使用原子变量a的释放 - 获取同步;因此,如果n = 2,那么在值2到y的释放存储与值3到y的宽松存储之间存在先发生关系。这是不是意味着 是一个释放序列,而k = 3,m = 1和n = 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);
          a.store(2, memory_order_release);
        }
      |||
        {
          a.load(memory_order_acquire).readsvalue(2);
          y.store(3, memory_order_relaxed);
        }
      }}}
    }
    
    <{3>} http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/ 导致1次一致的执行:

    enter image description here

    原因是从节点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);
        }
      }}}
    }
    

    然后没有一致的执行,即:

    enter image description here

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

0 个答案:

没有答案