Thread 1
Thread 2
public void frob() {
public void tweek() {
synchronized (one)
synchronized (two)
synchronized (two) {...}
synchronized (one) {...}
}
}
Figure 7-8. Typical Deadlock
Although typically a two-thread problem, deadlocks can involve dozens of threads in a circle, all
waiting for one another. They can involve a single thread that tries to obtain the same
(nonrecursive) mutex twice, and they can involve a thread that holds a lock dying while another
thread is waiting for it.
Deadlocks can always be avoided simply by using careful programming practices. If you declare a
lock hierarchy and always acquire locks in the same order--A before B before C, etc.--then there
is no chance of a deadlock. When you want to do out-of-order locking, you can use the trylock
functions to see whether you can get all the locks you need, and if not, then release them all and
Example 7-8 Locking Mutexes Out of Order
pthread_mutex_lock(&m2);
...
if (EBUSY == pthread_mutex_trylock(&m1)) {
pthread_mutex_unlock(&m2);
pthread_mutex_lock(&m1);
pthread_mutex_lock(&m2);
}
do_real_work();
/* Got 'em both! */
A typical instance of this out-of-order locking is the Solaris virtual memory system, which must
lock access to pages. There is an official hierarchy which says that page 1 must be locked before
page 2, etc. Occasionally, the VM system will lock page 2 and then discover that it also wants
page 1. It will then execute a trylock on page 1. If that succeeds, all is well and it proceeds. If it
fails, it releases the lock on page 2 and requests the locks in proper order.[3] This is a simple
optimization that saves a bit of time in the normal case and is always correct.
[3]
Note that you must release lock m2. Just spinning, waiting for m1 to become available, will not
work.
Search WWH :