带内存排序的C ++原子增量

时间:2017-08-11 14:43:29

标签: c++ concurrency atomic memory-barriers

在我阅读第5章中的C ++并发后,我尝试编写一些代码来测试我对内存排序的理解:

#include <iostream>
#include <vector>
#include <thread>
#include <atomic>

std::atomic<int> one,two,three,sync;

void func(int i){
    while(i != sync.load(std::memory_order_acquire));
    auto on = one.load(std::memory_order_relaxed); ++on;
    auto tw = two.load(std::memory_order_relaxed); ++tw;
    auto th = three.load(std::memory_order_relaxed); ++th;
    std::cout << on << tw << th << std::endl;
    one.store(on,std::memory_order_relaxed);
    two.store(tw,std::memory_order_relaxed);
    three.store(th,std::memory_order_relaxed);
    int expected = i;
    while(!sync.compare_exchange_strong(expected,i+1,
            std::memory_order_acq_rel))
        expected = i;
}

int main(){
    std::vector<std::thread> t_vec;
    for(auto i = 0; i != 5; ++i)
        t_vec.push_back(std::thread(func,i));
    for(auto i = 0; i != 5; ++i)
        t_vec[i].join();
    std::cout << one << std::endl;
    std::cout << two << std::endl;
    std::cout << three << std::endl;
    return 0;
}

我的问题是:本书说memory_order_release和memory_order_acquire应该是一对来正确读取正确的值。

因此,如果func()的第一行在带有memory_order_acquire的循环中加载同步,它应该会破坏该对并在同步时产生不可预测的错误。

然而,正如预期的那样,它在我的x86平台上编译后打印:

111
222
333
444
555
5
5
5

结果显示没问题。所以我只是想知道func()中发生了什么(虽然我自己写了......)?

已添加:根据第141页的操作中的C ++并发代码:

#include <atomic>
#include <thread>

std::vector<int> queue_code;
std::atomic<int> count;

void populate_queue(){
    unsigned const number_of_items = 20;
    queue_data.clear();
    for(unsigned i = 0; i < number_of_items; ++i)
        queue_data.push_back(i);
    count.store(number_of_items, std::memory_order_release);
}

void consume_queue_items(){
    while(true){
        int item_index;
        if((item_index=count.fetch_sub(1,memory_order_acquire))<=0){
            wait_for_more_items();
            continue;
        }
        process(queue_data[item_index-1]);
    }
}

int main(){
    std::thread a(populate_queue);
    std::thread b(consume_queue_items);
    std::thread c(consume_queue_items);
    a.join();
    b.join();
    c.join();
}

无论谁首先访问计数,线程b和线程c都可以正常工作。这是因为:

  

值得庆幸的是,第一个fetch_sub()确实参与发布 序列,因此store()与第二个fetch_sub()同步。两个消费者线程之间仍然没有同步关系   链中可以有任意数量的链接,但如果它们都是读取 - 修改 - 写入操作,例如fetch_sub(),则store()仍将与标记为memory_order_acquire的每个链接同步。在此示例中,所有链接是相同的,并且都是获取操作,但它们可能是具有不同memory_ordering语义的不同操作的混合。

但我找不到相关的相关信息,如何读取 - 修改 - 写操作如fetch_sub()参与发布序列?如果我将其更改为使用memory_order_acquire加载,那么store()是否仍会在每个独立线程中与load()同步?

0 个答案:

没有答案