System Model

Deadlock in Multithreaded Applications

pthread_mutex_t first_mutex;
pthread_mutex_t second_mutex;

pthread_mutex_init(&first_mutex, NULL);
pthread_mutex_init(&second_mutex, NULL);

/* thread_one runs in this function */
void *do_work_one(void *param)
{
    pthread_mutex_lock(&first_mutex);
    pthread_mutex_lock(&second_mutex);
    /*
    * Do some work
    */
    pthread_mutex_unlock(&second_mutex);
    pthread_mutex_unlock(&first_mutex);

    pthread_exit(0);
}

/* thread_two runs in this function */
void *do_work_two(void *param)
{
    pthread_mutex_lock(&second_mutex);
    pthread_mutex_lock(&first_mutex);
    /*
    * Do some work
    */
    pthread_mutex_unlock(&first_mutex);
    pthread_mutex_unlock(&second_mutex);

    pthread_exit(0);
}

Deadlock Characterization

Resource-Allocation Graph

Example
Resource-allocation graph for program in upper example code
Resource-allocation graph
Resource-allocation graph
DeadlockGraph
Resource-allocation graph with a deadlock
DeadlockGraph
Resource-allocation graph with a cycle but no deadlock

Methods for Handling Deadlocks

Deadlock Prevention

/* Deadlock example with lock ordering */

void transaction(Account from, Account to, double amount)
{
    mutex lock1, lock2;
    lock1 = get_lock(from);
    lock2 = get_lock(to);

    acquire(lock1);
        acquire(lock2);

            withdraw(from, amount);
            deposit(to, amount);

        release(lock2);
    release(lock1);
}

transaction(checking_account, saving_account, 25.0);
transaction(saving_account, checking_account, 50.0);

Deadlock Avoidance

Safe State

State
Safe, unsafe, and deadlocked state spaces

Revisit the Resource-Allocation Graph

Graph1
Resource-allocation graph for deadlock avoidance
Graph2
An unsafe state in a resource-allocation graph

Banker's Algorithm

An Illustrative Example

Snapshot1
Snapshot2
/* Sequence of Safety Algorithm */

Work = {3, 3, 2}
Finish = {false, false, false, false, false} // T1 ~ T0

i = 0,
Need[0] = {7, 4, 3}
Need[0] <= Work is false

i = 1,
Need[1] = {1, 2, 2}
Need[1] <= Work is true
update Work = Work + Allocation[1] = {5, 3, 2}
update Finish = {false, true, false, false, false} 

i = 2, 
Need[2] = {6, 0, 0}
Need[2] <= Work is false

i = 3,
Need[3] = {0, 1, 1}
Need[3] <= Work is true
update Work = Work + Allocation[3] = {7, 4, 3}
update Finish = {false, true, false, true, false} 

i = 4,
Need[4] = {4, 3, 1}
Need[4] <= Work is true
update Work = Work + Allocation[4] = {7, 4, 5}
update Finish = {false, true, false, true, true} 

i = 0,
Need[0] = {7, 4, 3}
Need[0] <= Work is true
update Work = Work + Allocation[0] = {7, 5, 5}
update Finish = {true, true, false, true, true} 

i = 2, 
Need[2] = {6, 0, 0}
Need[2] <= Work is true
update Work = Work + Allocation[2] = {10, 5, 7}
update Finish = {true, true, true, true, true} 

all elements in Finish vector are true
Snapshot3

Deadlock Detection

Graphs
(a) Resource-allocation graph (b) Corresponding wait-for graph

Detection Algorithm

An Illustrative Example

Snapshot4
Snapshot5

Recovery from Deadlock