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

时间:2015-04-16 04:17:52

标签: c++ c++11 volatile

从此处volatile的定义中删除m_flag是否安全? 如果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();
}

2 个答案:

答案 0 :(得分:10)

通常,volatile和多线程在C ++ 11中是正交的。使用volatile既不会添加也不会删除数据争用。

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

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

编译器&#34;优化&#34;无论是否使用volatile,这种情况都是不合格的。

答案 1 :(得分:1)

你在循环中调用了wait,所以编译器无法消除它。除了wait对编译器可能或多或少是不透明的事实外,它在其中包含互斥锁定/解锁,这有效地防止了编译器的任何消除。所以volatile在那里完全无用。