Let's say I have two variables, protected_var1
and protected_var2
. Let's further assume that these variables are updated via multiple threads, and are fairly independent in that usually one or the other but not both is worked on – so they both have their own mutex guard for efficiency.
Assuming:
-I always lock mutexes in order (mutex1 then mutex2) in my code in regions where both locks are required.
-Both mutexes are used many other places by them selves (like just lock mutex1, or just lock mutex2).
Does the order in which I unlock the mutexes at the end of a function using both make a difference in this situation?
void foo()
{
pthread_mutex_lock(&mutex1);
pthread_mutex_lock(&mutex2);
int x = protected_var1 + protected_var2;
pthread_mutex_unlock(&mutex1); //Does the order of the next two lines matter?
pthread_mutex_unlock(&mutex2);
}
I was asked a question a long time ago in an interview regarding this situation, and I came out feeling that the answer was yes – the order of those two unlocks does matter. I cannot for the life of me figure out how a deadlock could result from this though if the locks are always obtained in the same order wherever both are used.
Best Answer
The order shouldn't matter, as long as you don't attempt to acquire another lock between the releases. The important thing is to always acquire the locks in the same order; otherwise, you risk a deadlock.
EDIT:
To expand on the constraint: You must establish a strict ordering among the mutexes, e.g.
mutex1
precedesmutex2
(but this rule is valid for any number of mutexes). You may only request a lock on a mutex if you don't hold a mutex which comes after it in the order; e.g. you may not request a lock onmutex1
if you hold a lock onmutex2
. Anytime these rules are respected, you should be safe. With regards to releasing, if you releasemutex1
, then try to reacquire it before releasingmutex2
, you've violated the rule. In this regard, there may be some advantage in respecting a stack-like order: last acquired is always the first released. But it's sort of an indirect effect: the rule is that you cannot request a lock onmutex1
if you hold one onmutex2
. Regardless of whether you had a lock onmutex1
when you acquired the lock onmutex2
or not.