mercredi 25 janvier 2017

Is std::mutex sequentially consistent?

Say, I have two threads A and B writing to a global Boolean variables fA and fB respectively which are initially set to false and are protected by std::mutex objects mA and mB respectively:

// Thread A
mA.lock();
assert( fA == false );
fA = true;
mA.unlock();

// Thread B
mB.lock()
assert( fB == false );
fB = true;
mB.unlock()

Is it possible to observe the modifications on fA and fB in different orders in different threads C and D? In other words, can the following program

#include <atomic>
#include <cassert>
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;

mutex mA, mB, coutMutex;
bool fA = false, fB = false;

int main()
{
    thread A{ []{
            lock_guard<mutex> lock{mA};
            fA = true;
        } };
    thread B{ [] {
            lock_guard<mutex> lock{mB};
            fB = true;
        } };
    thread C{ [] {
            mA.lock();
            const auto gA = fA;
            mA.unlock();
            mB.lock();
            const auto gB = fB;
            mB.unlock();
            lock_guard<mutex> lock{coutMutex};
            cout << "Thread C: gA = " << gA << ", gB = " << gB << endl;
        } };
    thread D{ [] {
            mA.lock();
            const auto gA = fA;
            mA.unlock();
            mB.lock();
            const auto gB = fB;
            mB.unlock();
            lock_guard<mutex> lock{coutMutex};
            cout << "Thread D: gA = " << gA << ", gB = " << gB << endl;
        } };
    A.join(); B.join(); C.join(); D.join();
}

legally print

Thread C: gA = 1, gB = 0
Thread D: gA = 0, gB = 1

according to the C++ standard?

Note: A spin-lock can be implemented using std::atomic<bool> variables using either sequential consistent memory order or acquire/release memory order. So the question is whether an std::mutex behaves like a sequentially consistent spin-lock or an acquire/release memory order spin-lock.

Aucun commentaire:

Enregistrer un commentaire