While the other answer is the key to not introducing a race condition, there is no reason to drop exception safety and error-resilience that comes from using the proper RAII wrappers like std::lock_guard<>
and std::unique_lock<>
.
You'd want to write:
if (auto lk = try_to_lock(mx)) {
std::cout << "simple test\n";
} // automatically unlocks at scope exit
And you can. Here's my simple implementation:
template <typename Lockable>
std::unique_lock<Lockable> try_to_lock(Lockable& lockable) {
return std::unique_lock<Lockable> (lockable, std::try_to_lock);
}
Live On Coliru
#include <mutex>
#include <iostream>
int main() {
// demo
std::mutex mx;
if (auto lk = try_to_lock(mx)) {
std::cout << "simple test\n";
} // automatically unlocks at scope exit
if (auto lk = try_to_lock(mx)) {
std::cout << "yes\n";
if (auto lk = try_to_lock(mx)) {
std::cout << "oops?!\n"; // not reached
} else {
std::cout << "no recursive lock\n";
}
// but you can manipulate the lock if you insist:
lk.unlock();
if (auto lk = try_to_lock(mx)) {
std::cout << "now we can lock again\n";
} else {
std::cout << "oops?!\n"; // not reached
}
}
}
Prints:
simple test
yes
no recursive lock
now we can lock again