C++ 并发 - memory_order_acquire

问题描述 投票:0回答:1
#include <atomic>
#include <thread>
std::vector<int> queue_data;
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,std::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(); 
}

这是《C++ 并发实践》一书第 5.3.4 节中的代码片段。

作者这么说

没有释放顺序规则或内存_顺序_释放 fetch_sub 操作,没有什么需要 存储到queue_data对第二个消费者是可见的,并且您 将会发生数据竞赛。

我不明白为什么我们需要在 fetch_sub 上释放来同步存储的数据(当然我们需要同步计数以避免重复处理)但是为什么第二个消费者不与

populate_queue
线程的释放同步?

c++ multithreading concurrency stdthread
1个回答
0
投票

我不明白为什么我们需要在fetch_sub上发布

你不知道。请注意,代码使用了获取并表示这是可以的。

为什么第二个消费者不与 populate_queue 线程的释放同步?

确实如此。

注意书中引用的内容(强调我的):

如果 fetch_sub 操作没有释放顺序规则或内存_顺序_释放,

发布顺序规则是怎么说的,引用自标准:

以原子对象 M 上的释放操作 A 为首的释放序列是 M 的修改顺序中副作用的最大连续子序列,其中第一个操作是 A,后续的每个操作都是原子读取-修改-写操作

因此,您拥有以下形式的发布序列:生产者 -> 消费者 1 -> 消费者 2。重点是,消费者 1 覆盖

count
的值不会破坏发布顺序,因此消费者 2 仍然与生产者同步。

© www.soinside.com 2019 - 2024. All rights reserved.