std::lock is used to prevent deadlock, right? However in my testing, it still caused deadlock. Could you check my test code to see if I used it incorrectly?
std::mutex m1;
std::mutex m2;
void func1()
{
std::unique_lock<std::mutex> lock1(m1, std::defer_lock);
printf("func1 lock m1\n");
std::this_thread::sleep_for(std::chrono::seconds(2));
std::unique_lock<std::mutex> lock2(m2, std::defer_lock);
printf("func1 lock m2\n");
std::lock(m1, m2);
printf("func1 std lock\n");
}
void func2()
{
std::unique_lock<std::mutex> lock1(m2, std::defer_lock);
printf("func2 lock m2\n");
std::this_thread::sleep_for(std::chrono::seconds(2));
std::unique_lock<std::mutex> lock2(m1, std::defer_lock);
printf("func2 lock m1\n");
std::lock(m2, m1);
printf("func2 std lock\n");
}
int _tmain(int argc, _TCHAR* argv[])
{
std::thread th1(func1);
std::thread th2(func2);
th1.join();
th2.join();
return 0;
}
The output is : func1 lock m1 func2 lock m2 func2 lock m1 func1 lock m2 func2 std lock
Then console hung...
std::lock avoids deadlock Instead of calling . lock() on the mutex itself, you can pass several mutexes as arguments to the function std::lock , which magically acquires the locks in an order that avoids deadlock. For example: #include <mutex> std::mutex a; std::mutex b; void worker1() { std::lock(a, b); ... a.
One of the most common ways of avoiding a deadlock is to always lock the two mutexes in the same order. If we always lock mutex A before mutex B, then we'll never have a deadlock.
A problem exists if two threads attempt to claim both resources but lock the associated mutexes in different orders. For example, if the two threads lock mutexes 1 and 2 respectively, a deadlock occurs when each attempts to lock the other mutex.
Nothing can change, so this is a permanent blocking of the threads, and a deadlock. This kind of deadlock is avoided by establishing an order in which locks are acquired (a lock hierarchy). When all threads always acquire locks in the specified order, this deadlock is avoided.
I think what you're trying to do doesn't work: You cannot silently modify the mutex underneath the unique lock. According to the specification, the "deferred" constructor makes the lock guard "not owning", and you cannot change that:
unique_lock(mutex_type& m, defer_lock_t) noexcept;
Effects: Constructs an object of type
unique_lock
.Postconditions:
pm == addressof(m)
andowns == false
.
The only way to modify the exposition-only owns
variable is by acting on the unique lock. The unique lock does not magically inspect the state of the held mutex.
The correct code should pass the unique lock to the std::lock
algorithm:
std::lock(lock1, lock2);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With