Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple locks with mutex and the possibility of a deadlock

I'm new to threads and trying to understand the mutex.
I understand mutex as some object ( key ) which is picked by only one thread ( if it's picked then the other threads can't pick it and have to wait ) to access some part of code which we want to lock.
So only one thread has access to that locked part of code at the time ( for example shared counter ). The other threads will have to wait until mutex is unlocked and so on.

Mutex1.Lock();
 {
     Mutex2.Lock();
     {
          // Code locked by mutex 1 and 2.
     }
     Mutex2.Unlock();

     // Code locked by mutex 1.
 }
 Mutex1.Unlock();

What happens if I write multiple mutex locks?
Will both mutexes get picked by the same thread? I also read that multiple mutex locks may cause deadlock.
Could anyone explain and provide me an example of how could I cause deadlock by locking part of code with 2 mutexes?

like image 245
stilltryingbutstillsofar Avatar asked Mar 10 '17 13:03

stilltryingbutstillsofar


People also ask

Is deadlock possible in mutex?

Deadlock is possible if thread1 acquires mutex1 while thread2 acquires mutex2. Even though deadlock is possible, it will not occur if thread1 can acquire and release the mutex locks for mutex1 and mutex2 before thread2 tries to acquire the locks. Of course, CPU scheduler scheduled the order in which the threads run.

What happens when mutex lock is used more than once?

If a thread which had already locked a mutex, tries to lock the mutex again, it will enter into waiting list of that mutex which results in deadlock.

How many mutexes does it take for 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.

Can multiple threads lock the same mutex?

The short answer is "yes".


2 Answers

Here's the safe way to code what you describe:

std::mutex Mutex1;
std::mutex Mutex2;

void
test()
{
    using namespace std;
    lock(Mutex1, Mutex2);  // no deadlock!
    lock_guard<mutex> lk1{Mutex1, adopt_lock};
    {
        lock_guard<mutex> lk2{Mutex2, adopt_lock};
        // Code locked by mutex 1 and 2.
    }   // lk2.unlock()
    // Code locked by mutex 1.
}   // lk1.unlock()

This code can't deadlock because std::lock(Mutex1, Mutex2) locks both mutexes while avoiding deadlock (by some internal algorithm). An advantage of using std::lock is that you don't have to remember what order you need to lock your mutexes in (which makes maintenance easier in a large code base). But the disadvantage is that you need to lock both locks at a single point in your code. If you can't lock them at the same time, then you have to fall back to ordering as the other answers describe.

This code is also exception safe in that if any exception is thrown anywhere, whatever happens to be locked is unlocked as the exception propagates out.

like image 165
Howard Hinnant Avatar answered Oct 27 '22 17:10

Howard Hinnant


A thread can hold multiple locks, yes. And a deadlock might occur indeed even if it has acquired only one mutex.. Look at the workflow:

Thread A

. 
.
.
lock mutex1
.
<---- Context switch! ----->

Thread B

.
.
.
.
lock mutex2
.
.
.
try lock mutex1 ----> BLOCKED UNTIL THREAD A RELEASES LOCK!

Thread A

.
.
.
try lock mutex2 ---> BLOCKED UNTIL THREAD B RELEASES LOCK!

DEADLOCK!

Read this, some mutex types, like the PTHREAD_MUTEX_NORMAL might cause a thread to deadlock it self as well.

.
.
.
lock mutex
.
.
.
try lock
like image 35
Tony Tannous Avatar answered Oct 27 '22 17:10

Tony Tannous