Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::lock still caused deadlock

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

like image 252
tillman Avatar asked Aug 22 '17 15:08

tillman


People also ask

How does std :: lock avoid deadlock?

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.

How to avoid deadlock in c++?

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.

Can mutex cause 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.

How to avoid deadlocks?

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.


1 Answers

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) and owns == 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);
like image 122
Kerrek SB Avatar answered Oct 13 '22 01:10

Kerrek SB