Discussion questions: deadlocks

Please work out these problems before your next discussion section. The GSIs will go over these problems during the discussion section.

You have learned the four necessary conditions for deadlock:

Deadlock prevention schemes work by attempting to remove one (or more) of these conditions. In this homework, you will look at two such methods.

You are developing a multithreaded bank software package. Suppose you have a method for transferring funds from one account to another. Each user account has a lock associated with it.

You must acquire the lock for both accounts before transferring funds, to ensure the money transfer is atomic. The transfer function prototype is:

transfer_money( int from_account_id, int to_account_id, int amount );

Here is an incorrect solution:

/*
 * An array of locks that ranges over account numbers.
 * locks[i] = lock for account i
 */
vector locks;

void transfer_money(int acct1, int acct2, int amount) {
    thread_lock(locks[acct1]);
    thread_lock(locks[acct2]);
    <transfer money>
    thread_unlock(locks[acct2]);
    thread_unlock(locks[acct1]);
}
For example, thread 1 could execute transfer_money(1, 2, 20), and thread 2 could execute transfer_money(2, 1, 100).

1. How can this deadlock?

2. Attacking the circular wait condition

Rewrite transfer_money() to be deadlock-free, by making a circular wait impossible. (Hint: define an ordering for the locks.)

3. Attacking the hold-and-wait condition

Rewrite transfer_money() again, this time avoiding any possible deadlock by removing the hold-and-wait condition. (Hint: each thread should either acquire both locks at once, or not at all). You may define new shared variables and/or new locks and condition variables. Your solution should not busy-wait.