Search code examples
c++mutexatomicmemory-barriersstdmutex

Why std::mutex of c++11 has no memory order?


I mean compared with c++11 atomic, for example:

#include <iostream>
#include <thread>
#include <atomic>

std::atomic<int> counter(0);

void incrementCounter() {
    for (int i = 0; i < 1000; ++i) {
        counter.fetch_add(1, std::memory_order_relaxed);
    }
}

int main() {
    std::thread t1(incrementCounter);
    std::thread t2(incrementCounter);

    t1.join();
    t2.join();

    std::cout << "Final counter value: " << counter << std::endl;

    return 0;
}

In the usage of std::atomic, we need to pass memory order parameters. Why doesn't std::mutex have this parameter and what's the default memory order of std::mutex ?


Solution

  • Correct usage of mutexes gives sequential consistency for data-race free programs (if they don't use any atomics weaker than seq_cst), even though the mutex lock / unlock themselves are only acquire and release operations. (This is where the names come from for those lock-free atomic memory orders.)

    So there's no need to make them stronger.

    And as Igor pointed out, they'd be useless if any weaker than release and acquire: relaxed would give no ordering wrt. operations on other variables, so wouldn't contain them to critical sections.

    std::memory_order_consume instead of acquire wouldn't be usable because you can't read the mutex value to use it as part of the address calculation for a later load. (If you want to mess around with a lock designed that way to see if it's viable, you'd have to roll it yourself using std::atomic, but current compilers promote consume to acquire. It's currently deprecated: the original design proved too hard to implement correctly + efficiently, and too cumbersome to use with std::kill_dependency, etc.)