【问题标题】:Volatile in C++11 - follow-upC++11 中的 Volatile - 后续
【发布时间】:2012-10-04 10:29:08
【问题描述】:

这是Volatile in C++11的后续行动

在问题中,有人告诉我以下代码在 C++11 中表现出未定义的行为,这让我非常困惑。关于 C++11 中 volatile 的行为,我是否可以阅读任何材料(也许是标准的部分)?

或者谁能解释一下问题出在哪里?

#include <iostream>
#include <chrono>
#include <thread>
using namespace std;

volatile int notify;

void watcher()
{
    this_thread::sleep_for(chrono::seconds(2));
    notify = 1;
    cout << "Notification sent." << endl;
}

int main()
{
    thread(watcher).detach();

    notify = 0;
    while (!notify)
    {
        cout << "Waiting." << endl;
        this_thread::sleep_for(chrono::seconds(1));
    }

    cout << "Notification received." << endl;

    return 0;
}

【问题讨论】:

    标签: c++ c++11 volatile


    【解决方案1】:

    该标准描述了内存模型,尤其是“数据竞争”的概念(第 1.10 节)。很明显,您的代码对变量 notify 存在数据竞争,因此行为未定义。

    要解决此问题,要么通过锁保护对notify 的访问,要么将其设置为原子变量,例如std::atomic&lt;int&gt;

    【讨论】:

    • 太棒了,我终于找到了标准的特定部分:“如果其中一个修改内存位置而另一个访问或修改相同的内存位置,则两个表达式计算冲突。” “如果程序的执行包含不同线程中的两个冲突操作,则该程序的执行包含数据竞争,其中至少一个不是原子的,并且两者都不会在另一个之前发生。任何此类数据竞争都会导致未定义的行为。”
    • 哇。这是一个非常非常严格的规则。
    • 嗯,我有点想知道您将如何编写一个使用此规则的线程库。基本上迫使您依赖编译器 ABI。我想你无论如何都必须这样做......
    • @Let_Me_Be:例如,你可以使用原子变量来构造一个锁定原语。
    • 等一下...是否有一个理智的编译器/实现,其中 notify 的值不是 0 或 1?我对这段代码的直觉反应是“这很好......不是最快的通知方式,但它会起作用”。其实不用volatile也不应该没问题吧?
    猜你喜欢
    • 2018-07-29
    • 2015-09-28
    • 2017-03-15
    • 2020-05-22
    • 2014-01-17
    • 2016-11-29
    • 1970-01-01
    • 2017-08-09
    • 1970-01-01
    相关资源
    最近更新 更多