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?
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.
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.
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.
The short answer is "yes".
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.
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
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