Deadlock

We looked at an example earlier detailing the way data can become corrupted if two threads are trying to access it at the same time. One of the principal concerns in a multi-threaded application is to ensure that such a data corruption scenario does not occur. We also need to be very careful to avoid race conditions and deadlock.

A race condition exists when the success of your operation depends on which of two threads finishes its task first, and the two threads operate independently of one another.

Assume one thread is responsible for initializing your printer, and another is responsible for adding a print job. The one that adds the print job must first make sure the printer is ready, or throw an exception if it is not. If the two threads are uncoordinated, some times the initialization will happen first and the job will print. Other times, however, the attempt to print will precede the initialization and thus will fail. 

Overall, the system will fail about half the time, and this will be terribly difficult to debug as it will be hard to reproduce reliably. Programmers hate flaky problems; we like systems which either work, or fail reliably. Race conditions breed unreliability.

Deadlock exists when thread A is blocked, waiting for thread B to take an action, but thread B is blocked waiting for thread A to take another action.

Assume you have a function to record a customer's deposit in the bank, which works as follows:

  1. Lock the customer record

  2. Lock the bank account record

  3. Update the bank account

  4. Update the customer

  5. Unlock the bank account

  6. Unlock the customer

You have a second function to compute the month end statement which works as follows:

  1. Lock the bank account record

  2. Lock the customer record

  3. Update the customer

  4. Update the bank account

  5. Unlock the customer

  6. Unlock the bank account

Both of these are well behaved, that is, they unlock in the reverse order in which they lock. Now imagine this scenario: thread A is running the first algorithm and thread B is running the second.

Thread A: lock the customer record

Thread B: lock the bank account record

Thread A: try to lock the bank account — block waiting for thread B to release

Thread B: try to lock the customer record — block waiting for thread A to release

You are stuck. This is a deadlock (often called a deadly embrace). There is nothing either thread can do to get free except, if you are lucky, to time out.

© 1998 by Wrox Press. All rights reserved.