代码之家  ›  专栏  ›  技术社区  ›  choxsword

原子操作的副作用能立即被其他线程看到吗?

  •  0
  • choxsword  · 技术社区  · 6 年前

    this question 一个回复者说

    原子性意味着操作要么完全执行 所有的副作用都是显而易见的 ,或者根本不执行。

    但是,下面是 并发操作$lising 5.5

    #include <thread>
    #include <atomic>
    #include <iostream>
    std::atomic<int> x(0),y(0),z(0);
    std::atomic<bool> go(false);
    unsigned const loop_count=10;
    struct read_values
    {
      int x,y,z;
    };
    read_values values1[loop_count];
    read_values values2[loop_count];
    read_values values3[loop_count];
    read_values values4[loop_count];
    read_values values5[loop_count];
    void increment(std::atomic<int>* var_to_inc,read_values* values)
    {
      while(!go)
      std::this_thread::yield();
      for(unsigned i=0;i<loop_count;++i)
      {
        values[i].x=x.load(std::memory_order_relaxed);
        values[i].y=y.load(std::memory_order_relaxed);
        values[i].z=z.load(std::memory_order_relaxed);
        var_to_inc->store(i+1,std::memory_order_relaxed);
        std::this_thread::yield();
      }
    }
    
    void read_vals(read_values* values)
    {
      while(!go)
      std::this_thread::yield();
      for(unsigned i=0;i<loop_count;++i)
      {
        values[i].x=x.load(std::memory_order_relaxed);
        values[i].y=y.load(std::memory_order_relaxed);
        values[i].z=z.load(std::memory_order_relaxed);
        std::this_thread::yield();
      }
    }
    void print(read_values* v)
    {
      for(unsigned i=0;i<loop_count;++i)
      {
        if(i)
        std::cout<<",";
        std::cout<<"("<<v[i].x<<","<<v[i].y<<","<<v[i].z<<")";
      }
      std::cout<<std::endl;
    }
    int main()
    {
      std::thread t1(increment,&x,values1);
      std::thread t2(increment,&y,values2);
      std::thread t3(increment,&z,values3);
      std::thread t4(read_vals,values4);
      std::thread t5(read_vals,values5);
      go=true;
      t5.join();
      t4.join();
      t3.join();
      t2.join();
      t1.join();
      print(values1);
      print(values2);
      print(values3);
      print(values4);
      print(values5);
    }
    

    作者给出的示例输出是

    (0,0,0),(1,0,0),(2,0,0),(3,0,0),(4,0,0),(5,7,0),(6,7,8),(7,9,8),(8,9,8),(9,9,10)
    (0,0,0),(0,1,0),(0,2,0),(1,3,5),(8,4,5),(8,5,5),(8,6,6),(8,7,9),(10,8,9),(10,9,10)
    (0,0,0),(0,0,1),(0,0,2),(0,0,3),(0,0,4),(0,0,5),(0,0,6),(0,0,7),(0,0,8),(0,0,9)
    (1,3,0),(2,3,0),(2,4,1),(3,6,4),(3,9,5),(5,10,6),(5,10,8),(5,10,10),(9,10,10),(10,10,10)
    (0,0,0),(0,0,0),(0,0,0),(6,3,7),(6,5,7),(7,7,7),(7,8,7),(8,8,7),(8,8,9),(8,8,9)  
    

    输出似乎是一个线程中的修改 其他线程无法立即看到 .

    作者还说:

    螺纹3 没有看到对x或y的任何更新; 它只看到更新 使为z。这不会阻止其他线程查看对z的更新 不过,也加入了对x和y的更新。

    我很困惑为什么thread3没有看到 x y 是的。那是不是意味着 原子操作的副作用是可见的 不是真的吗?这是否遵循由计算机硬件保证的缓存一致性规则?

    0 回复  |  直到 6 年前