The curious case of recursive mutex
Mutex…ahh the things that are used to synchronize access to critical code/section. If that’s what first comes to your mind when you hear the word “Mutex” in computer programming then, you are right.
From Wikipedia : In computer science, a lock or mutex (from mutual exclusion) is a synchronization primitive: a mechanism that enforces limits on access to a resource when there are many threads of execution. A lock is designed to enforce a mutual exclusion concurrency control policy, and with a variety of possible methods there exists multiple unique implementations for different applications.
If you are an experienced system programmer then you might have heard the term recursive mutex, but for those who are unfamiliar with it, this blog is for them.
Now we have the definition out of the way let’s see on how to implement a regular mutex in a Linux environment in C.
pthread_mutex_t mutex;
void func(){ pthread_mutex_lock(&mutex);
//Critical Section code
pthread_mutex_unlock(&mutex);}
int main(){ pthread_mutex_init(&mutex,NULL);
return 0;}
We used three APIs namely : pthread_mutex_init, pthread_mutex_lock, pthread_mutex_unlock. While the later two are easy to understand just by their names(they are used to lock and unlock the mutex), the first API is where things get interesting. But first lets ask ourselves a question:-
What happens if a thread tries to take a lock on the mutex which the thread already holds the lock to?
void func(){ pthread_mutex_lock(&mutex);
func();// Recursive call
pthread_mutex_unlock(&mutex);}
The above example is a recursive function which first takes a lock on the mutex and then calls itself. The second time it tries to take a lock on the “mutex” object , it will go into a deadlock state as the thread is waiting for itself to finish and release the lock.
To overcome this, we can use recursive mutex. According to Wikipedia:-
In computer science, the reentrant mutex (recursive mutex, recursive lock) is a particular type of mutual exclusion (mutex) device that may be locked multiple times by the same process/thread, without causing a deadlock.
As the definition says, a recursive mutex allows a thread/process to take the lock on the same mutex multiple times without going into deadlock.(Keep in mind the mutex must be locked and unlocked from the same thread).
pthread_mutex_t mutex;int main(){
pthread_mutexattr_t attr; //Attribute variable
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mutex,&attr);
return 0;
}
This example illustrates how one can implement recursive mutex. The important variable here is “attr” which controls the behavior of the mutex. pthread_mutexattr_settype API allows to set the recursive nature. Now if this mutex is used in our previous example then there will be no deadlock . Make sure that the number of pthread_mutex_lock and pthread_mutex_unlocks are the same.
Please let me know if you find any errors or have any suggestions.
Links: pthread_mutexattr_settype, Recursive Mutex .