在这里删除 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
在那里完全没用。
在这里从 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
在那里完全没用。