Is it safe to remove volatile
from the definition of m_flag
here?
If m_flag
is not volatile, what would stop compilers from optimizing away this loop's condition: while (!m_flag) m_cv.wait(lock);
?
Does the standard (post-C++11) specify explictly that such optimizations are prohibited in such cases?
#include
#include
#include
#include
using namespace std;
class foofoo
{
volatile bool m_flag;
mutex m_mutex;
condition_variable m_cv;
public:
void DoWork()
{
m_flag = false;
unique_lock lock(m_mutex);
auto junk = async(std::launch::async, [this]()
{
{
unique_lock 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();
}
Answer
In general, volatile
and multithreading are orthogonal in C++11. Using volatile
neither adds nor removes data races.
In this case, m_flag = true;
is sequenced before the release of the mutex in the thread launched by async
([intro.execution]/p14), which in turn synchronizes with the subsequent acquire of the mutex in m_cv.wait(lock)
([thread.mutex.requirements.mutex]/p11,25), which in turn is sequenced before a subsequent read of m_flag
. m_flag = true;
therefore inter-thread happens before, and hence happens before, the subsequent read. ([intro.multithread]/p13-14)
Since there are no other side effects on m_flag
, m_flag = true;
is the visible side effect with respect to that read ([intro.multithread]/p15), and that read must therefore read what was stored by the visible side effect, i.e., true
.
A compiler that "optimizes" away that condition, regardless of whether volatile
is used, would be non-conforming.
No comments:
Post a Comment