Can thread t2
unlock a mutex m
, although the mutex was previously locked by thread t1
? Can the mutex m
be unlocked twice?
To illustrate these questions, I wrote the following little script:
#include <atomic>
#include <mutex>
#include <thread>
#include <iostream>
class spinlock_mutex {
std::atomic_flag flag;
public:
spinlock_mutex() : flag(ATOMIC_FLAG_INIT){};
void lock() {
while (flag.test_and_set(std::memory_order_acquire)) {
std::cout << "cloud not acquire lock" << std::endl;
}
std::cout << "acquired lock" << std::endl;
}
void unlock() {
flag.clear(std::memory_order_release);
std::cout << "release lock" << std::endl;
}
};
int main() {
spinlock_mutex mutex{};
std::lock_guard<spinlock_mutex> lock_a(mutex);
std::thread t2([&](){mutex.unlock();});
t2.join();
std::cout << "t2 has unlocked the mutex" << std::endl;
}
Execution of this code prints the following:
acquired lock
release lock
t2 has unlocked the mutex
release lock
It seems to me that the main thread acquired the mutex via the lock_guard
facility. Then, thread t2
unlocks the mutex. At the end of the main scope, the destructor of lock_guard
unlocks the lock (shouldn't that been unlocked by now?) again. (When I replace the custom spinlock_mutex
with std::mutex
the program runs without any complaints but of course does not print any information).
So I wonder if thread t2
can indeed unlock a mutex it has not locked, and which mutex does the main thread unlock at the end? cppreference warns of undefined behavior in the description of the unlock
function, and I wonder if the program documents this?