使用获取释放内存排序的传递同步

时间:2014-11-19 17:38:14

标签: c++

我一直在关注“C ++并发操作”一书中的示例,以更好地理解获取 - 发布模型,但我有一些问题:

std::atomic<int> data[3];
std::atomic<bool> sinc1(false), sinc2(false);

void thread_1() {
    data[0].store(1,std::memory_order_relaxed);
    data[1].store(2,std::memory_order_relaxed);
    data[2].store(3,std::memory_order_relaxed);
    sinc1.store(true,std::memory_order_release);
}

void thread_2() {   
    while(!sinc1.load(std::memory_order_acquire))
    sinc2.store(true,std::memory_order_release);
}

void thread_3() {      
    while(!sinc2.load(std::memory_order_acquire))     
    assert(data[0].load(std::memory_order_relaxed)==1);
    std::cout << data[0] << std::endl;
    assert(data[1].load(std::memory_order_relaxed)==2);
    std::cout << data[1] << std::endl;
    assert(data[2].load(std::memory_order_relaxed)==3);
    std::cout  << data[2] << std::endl;
}

int main() {    
    std::thread t1(thread_1);
    std::thread t2(thread_2);
    std::thread t3(thread_3);
    t1.join();
    t2.join();
    t3.join();

    return 0;
}

现在,sinc1中的商店发生了 - 在thread_2中的sinc1加载之前,在sinc2中的商店之前进行了排序。 sinc2中的存储形成另一个释放 - 获取对,在thread_3中加载sinc2,这在数据加载之前发生。 由于转换,thread_1中的数据存储发生在thread_3中的数据加载之前。 “断言不应该开火。

相反,当我运行它时,我会得到我所期望的,但有时候:

Assertion failed: (data[0].load(std::memory_order_relaxed)==1)....

我有两个问题:

  1. 我错过了什么吗?

  2. 当它没有失败时我得到了这些输出:

  3. 1 2 3  
    

    0 1 2
    

    sync1上的release-acquire内存模型是否应该在商店数据上给出一定的内存顺序?

    如果我想遵循严格的命令,为什么我会放松。

    我知道我可以使用放松和一起释放达到某个顺序。但显然它不起作用

    0 1 2

    有人可以向我澄清这些观点吗?

    谢谢。

2 个答案:

答案 0 :(得分:0)

来自cppreference

  

memory_order_relaxed 轻松排序:没有同步   或排序约束,此操作只需要原子性。

C ++ 14对订购有一些进一步的限制,这里不适用。

void thread_1() {
    data[0].store(1,std::memory_order_relaxed);
    data[1].store(2,std::memory_order_relaxed);
    data[2].store(3,std::memory_order_relaxed);

---上下文切换---

这些现在可以被&#34;随机&#34;中的其他线程看到。因为他们只保证原子操作。所以其他线程可以看到0 / 1,0 / 2,0 / 0的任意组合,例如0,2,0但不是0,1,2 ......除非数据在开始之前具有这些值,所以将第一行更改为

std::atomic<int> data[3] = { -1,-1,-1 }; // lets make sure we know what we have

thread_1完成

的最后一行之前
    sinc1.store(true,std::memory_order_release);
}

以前对内存的所有写操作都必须完成。

  

memory_order_release 具有此内存顺序的商店操作   执行释放操作:事先写入其他内存位置   对消费或获取的线程变得可见   同一地点。

幸运的是,thread_2在同一地点进行了获取

void thread_2() {   
    while(!sinc1.load(std::memory_order_acquire))  <----------- bug here missing ;
    sinc2.store(true,std::memory_order_release);
}

所以虽然!sinc1我们将sinc2设置为true,但我猜这不是你想要的。 为了避免这样的问题,总是放置{}。

答案 1 :(得分:0)

问题似乎是你的代码在while循环之后错过了;

但我不同意你的看法:在这两个地方使用分号,断言必须永远不会触发,代码将始终打印1 2 3