As just noted, the simplest (and best) approach to prevent deadlock to make certain that all threads that will hold multiple mutexes simultaneously obtain these mutexes in a prescribed order. Ordinarily this can be done, but occasionally it might turn out to be impossible.
For example, we might not know which mutex to take second until the first mutex has already been obtained.
To avoid deadlock in such situations, we can use the approach shown here:
proc1( ) { pthread_mutex_lock(&m1); /* use object 1 */ pthread_mutex_lock(&m2); /* use objects 1 and 2 */ pthread_mutex_unlock(&m2); pthread_mutex_unlock(&m1); } proc2( ) { while (1) { pthread_mutex_lock(&m2); if (!pthread_mutex_trylock(&m1)) break; pthread_mutex_unlock(&m2); } /* use objects 1 and 2 */ pthread_mutex_unlock(&m1); pthread_mutex_unlock(&m2); }
Here thread 1, executing proc1, obtains the mutexes in the correct order. Thread 2, executing proc2, must for some reason take the mutexes out of order. If it is holding mutex 2, it must be careful about taking mutex 1. So, rather than call pthread_mutex_lock, it calls pthread_mutex_trylock, which always returns without blocking. If the mutex is available, pthread_mutex_trylock locks the mutex and returns 0. If the mutex is not available (i.e., it is locked by another thread), then pthread_mutex_trylock returns a nonzero error code (EBUSY). In the example, if mutex 1 is not available, it is probably because it is currently held by thread 1. If thread 2 were to block waiting for the mutex, we have an excellent chance for deadlock. So, rather than block, thread 1 not only quits trying for mutex 1 but also unlocks mutex 2 (since thread 1 could well be waiting for it). It then starts all over again, first taking mutex 2, then mutex 1.