Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 <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();
}
like image 311
Max Galkin Avatar asked Apr 16 '15 04:04

Max Galkin


2 Answers

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.

like image 68
T.C. Avatar answered Oct 04 '22 00:10

T.C.


You have a call to wait inside the loop so there is no way for the compiler to eliminate it. Besides the fact that wait might be more-or-less opaque thing to the compiler it contains mutex lock/unlock inside it which effectively prevents compiler of any elimination. So volatile is totally useless there.

like image 37
ixSci Avatar answered Oct 03 '22 23:10

ixSci