在这里删除 c++ volatile 是否安全?

Is it safe to remove the c++ volatile here?

在这里从 m_flag 的定义中删除 volatile 是否安全? 如果 m_flag 不是易变的,什么会阻止编译器优化这个循环的条件: while (!m_flag) m_cv.wait(lock); ? 标准(post-C++11)是否明确规定在这种情况下禁止进行此类优化?

#include <mutex>
#include <condition_variable>
#include <future>
#include <iostream>
using namespace std;

class foofoo
{
    volatile bool m_flag;
    mutex m_mutex;
    condition_variable m_cv;

public:
    void DoWork()
    {
        m_flag = false;
        unique_lock<mutex> lock(m_mutex);
        auto junk = async(std::launch::async, [this]()
        {
            {
                unique_lock<mutex> lock(m_mutex);
                m_flag = true;
            }
            m_cv.notify_one();
        });
        while (!m_flag) m_cv.wait(lock);
        cout << "ququ" << endl;
    }
};

int main()
{
    foofoo f;
    f.DoWork();
}

一般来说,volatile和多线程在C++11中是正交的。使用 volatile 既不会增加也不会删除数据竞争。

在这种情况下,m_flag = true;在 由 async 启动的线程中 释放互斥量([intro.execution] /p14),它又 同步 m_cv.wait(lock) ([thread.mutex.requirements.mutex]/p11,25) 中互斥锁的后续获取,后者又是 的后续读取 m_flag 之前排序。 m_flag = true; 因此 线程间发生在 之前,因此 发生在 之前,随后的读取。 ([intro.multithread]/p13-14)

由于 m_flag 没有其他副作用,m_flag = true; 可见的副作用 相对于读取 ([intro.multithread]/p15),因此读取必须读取可见副作用存储的内容,即 true.

无论是否使用 volatile,"optimizes" 消除该条件的编译器都是不合格的。

您在循环内调用了 wait,因此编译器无法消除它。除了 wait 对编译器来说可能或多或少是不透明的事实之外,它内部还包含互斥体 lock/unlock ,这有效地防止了编译器的任何消除。所以 volatile 在那里完全没用。