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
?
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.)