从此处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();
}
答案 0 :(得分:10)
通常,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
。
编译器&#34;优化&#34;无论是否使用volatile
,这种情况都是不合格的。
答案 1 :(得分:1)
你在循环中调用了wait
,所以编译器无法消除它。除了wait
对编译器可能或多或少是不透明的事实外,它在其中包含互斥锁定/解锁,这有效地防止了编译器的任何消除。所以volatile
在那里完全无用。