简体   繁体   English

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

[英]Transitive synchronization using acquire-release memory ordering

I have been following an example in a Book "C++ Concurrency in Action" to better understand acquire-release model, but I have some issues : 我一直在遵循“ 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;
}

Now, the store in sinc1 happen-before the load in sinc1 in thread_2, which is sequenced-before the store in sinc2. 现在,sinc1中的存储发生在线程_2中sinc1中的加载(顺序化)之前,sinc2中的存储发生在先后。 The store in sinc2 forms another release-acquire pair with load in sinc2 in thread_3, which happens-before the load of data. sinc2中的存储与线程_3中的sinc2中的负载形成了另一个释放获取对,这在数据加载之前发生。 Because of transition, the store of data in thread_1 happens before of load of data in thread_3. 由于过渡,线程_1中的数据存储发生在线程_3中的数据加载之前。 The "asserts should NOT fire. “断言不应触发。

Instead when I run it sometime I get what i expect, but sometimes : 相反,当我在某个时候运行它时,我得到了期望的结果,但是有时:

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

I have 2 questions : 我有两个问题:

  1. Am I missing something ? 我想念什么吗?

  2. when it does not fail I got these output: 当它没有失败时,我得到了以下输出:

either : 要么:

1 2 3  

or 要么

0 1 2

Shouldn't the release-acquire memory model on sync1 give certain memory order on store data ? 同步1上的发布获取内存模型是否应该对存储数据给出特定的内存顺序?

Why do I use relaxed if I want follow a strick orders. 如果要遵循严格的命令,为什么要使用轻松的命令。

I understood I could reach certain order using relaxed and release together. 我知道使用放宽并放在一起可以达到一定的顺序。 But apparently it does not work 但是显然它不起作用

0 1 2 0 1 2

Someone could clarify me these points ? 有人可以向我阐明这些观点吗?

Thank you. 谢谢。

From cppreference 来自cppreference

memory_order_relaxed Relaxed ordering: there are no synchronization or ordering constraints, only atomicity is required of this operation. memory_order_relaxed宽松的排序:没有同步或排序约束,此操作仅需要原子性。

C++14 has some further restrictions on the ordering that should not be applicable here. 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);

---context switch--- ---上下文切换---

These can now become visible to the other threads in "random" order as they guarantee only atomic operations. 这些现在可以按“随机”顺序显示给其他线程,因为它们仅保证原子操作。 So the other threads can see any combination of 0/1, 0/2, 0/3 for example 0, 2, 0 but not 0, 1, 2 ... unless data had these values before start so change the first line to 因此,其他线程可以看到0 / 1、0 / 2、0 / 3的任意组合,例如0、2、0,但看不到0、1、2 ...的组合,除非数据在启动之前具有这些值,所以将第一行更改为

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

Before the last line in thread_1 finished thread_1的最后一行结束之前

    sinc1.store(true,std::memory_order_release);
}

All previous writes to memory must have finished. 以前所有对内存的写操作都必须完成。

memory_order_release A store operation with this memory order performs the release operation: prior writes to other memory locations become visible to the threads that do a consume or an acquire on the same location. memory_order_release具有此内存顺序的存储操作执行释放操作:在同一位置进行消耗或获取的线程可以看到对其他内存位置的先前写入。

Luckily thread_2 does an acquire on the same location 幸运的是thread_2在同一位置进行获取

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

So while !sinc1 we set sinc2 to true I guess that was not what you wanted. 因此,当!sinc1设置为sinc2时,我想那不是您想要的。 To avoid problems like this always put a {} behind while. 为避免出现此类问题,请务必在之后放置{}。

The problem seems to be that your code misses ; 问题似乎是您的代码遗漏了; after the while loops. 在while循环之后。

But otherwise I agree with you: with semicolons in both these places the assert must never fire and the code will always print 1 2 3 . 但是,否则我将与您达成一致:在这两个地方都使用分号时,断言绝不能执行,并且代码将始终显示1 2 3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM