Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Std::Lock avoids deadlock but this program gets stuck

All, Referring to the question in std::lock still caused deadlock

I still couldn't figure what is the problem in the below code. Can somebody please explain the problem and how to fix this? Why does it get hung? Pls help.

#include <iostream>
#include <mutex>
#include <thread>
using namespace std;

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(1));
    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(1));
    std::unique_lock<std::mutex> lock2(m1, std::defer_lock);
    printf("func2 lock m1\n");
    std::lock(m1, m2);
    printf("func2 std lock\n");
}



int main(int argc,char* argv[])
{
    std::thread th1(func1);
    std::thread th2(func2);
    th1.join();
    th2.join();
    return 0;
}

Output seen: func1 lock m1
func2 lock m2
func1 lock m2
func1 std lock
func2 lock m1
----- Hung here.

Why doesn't func2 proceed even though func1 has released both the mutexes?

like image 675
sudheerbb Avatar asked Nov 21 '19 10:11

sudheerbb


1 Answers

Instead of :

std::lock(m1, m2);

use :

std::lock(lock1, lock2);

More details (including an example) can be found on the reference page for std::lock.

Why does your code hang ?

When you call std::lock(m1, m2), the two mutexes are locked directly. Neither of the std::unique_locks (lock1 and lock2) are aware of this, and thus they can not unlock the mutexes.

So, when func1 ends both mutexes are still locked, and func2 cannot proceed past the std::lock(m1, m2) line.

Why does the fixed code work ?

When you call std::lock(lock1, lock2), the std::unique_locks (lock1 and lock2) are aware of this - they now own the locks, and are responsible for unlocking them (which happens when they go out of scope).

So, when func1 ends both mutexes are unlocked, and func2 can proceed past the std::lock(lock1, lock2) line. And all is well.

like image 101
Sander De Dycker Avatar answered Oct 26 '22 21:10

Sander De Dycker