微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

不明白为什么在 <C++ Concurrency in action>

如何解决不明白为什么在 <C++ Concurrency in action>

我目前在内存模型部分(第 5 章)中阅读了有关“C++ 并发操作”的内容。 在第 5.3.1 章,作者写道:

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

std::vector<int> data;
std::atomic<bool> data_ready(false);

void reader_thread()
{
    while(!data_ready.load())    // (1)
    {
        std::this_thread::sleep(std::milliseconds(1));
    }
    std::cout<<”The answer=”<<data[0]<<”\n”;    // (2) 
}

void writer_thread()
{
    data.push_back(42);  // (3)
    data_ready=true;     // (4) 
}

暂且不说循环等待数据的低效率 准备好(1),你真的需要这个来工作,因为否则共享数据 线程之间变得不切实际:每一项数据都被迫 是原子的。你已经知道这是未定义的行为 非原子读(2)和写(3)访问相同的数据而不用 强制排序,因此要使其起作用,必须强制执行 在某处订购。

所需的强制排序来自 std:: 上的操作: 原子变量 data_ready;他们提供必要的订购 由于内存模型关系发生在之前和 同步。数据的写入(3)发生在写入之前 到data_ready标志(4),和标志的读取(1) 发生在读取数据之前(2)。当值从 data_ready(1)为真,写与读同步, 创建一个发生在之前的关系。因为happens-before 是 可传递的,写入数据(3)发生在写入之前 标志(4),它发生在从真正的值中读取之前 标志(1),它发生在读取数据(2)之前,你有 强制排序:数据的写入发生在读取之前 数据和一切正常。图 5.2 显示了重要的 两个线程中的happens-before 关系。我添加了一对 来自读取器线程的 while 循环迭代次数

所有这些似乎都相当直观:当然是操作 写入值发生在读取该值的操作之前!和 认的原子操作,确实如此(这就是为什么这个 是认值),但它确实需要说明:原子操作 也有订购要求的其他选项,我会来 到不久

我很不明白,为什么“这一切看起来很直观:当然,写入值的操作发生在读取该值的操作之前!”,请帮助我理解这句话。

解决方法

写入值 (3) 的操作发生在读取值 (2) 的操作之后,因为 data_ready 标志。写入器线程在写操作后启用标志(4),而读取器线程在启用标志之前有一个不继续的循环。

编译器将原子加载或存储视为内存栅栏。使用原子变量的默认选项,编译器不会跨此栅栏重新排序操作。所以顺序总是 3 -> 4 ->(循环结束)-> 2。

如果使用其他选项,编译器可能会重新排列每个函数中的操作,以便 4 在 3 之前执行,或者 2 在 1 之前执行。

您可以将选项作为参数提供给 load()store()See the documentation.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。