/* first_mutex and second_mutex
are created and initialized. */
T1 waits on first_mutex; /* T1 holds first_mutex */
T2 waits on second_mutex; /* T2 holds second_mutex */
T1 waits on second_mutex; /* T1 has blocked */
T2 waits on first_mutex; /* T2 has blocked */
Now both threads are blocked forever - deadlocked.
/* thread_one runs in this function */
void *do_work_one(void *param)
{ int done = 0;
while (!done)
{ pthread_mutex_lock(&first_mutex);
if (pthread_mutex_trylock(&second_mutex))
{
/* Do some work */
pthread_mutex_unlock(&second_mutex);
pthread_mutex_unlock(&first_mutex);
done = 1;
}
else pthread_mutex_unlock(&first_mutex);
}
pthread_exit(0);
}
/* thread_two runs in this function */
void *do_work_two(void *param)
{ int done = 0;
while (!done)
{ pthread_mutex_lock(&second_mutex);
if (pthread_mutex_trylock(&first_mutex))
{
/* Do some work */
pthread_mutex_unlock(&first_mutex);
pthread_mutex_unlock(&second_mutex);
done = 1;
}
else pthread_mutex_unlock(&second_mutex);
}
pthread_exit(0);
}
thread max needs cur alloc needs left free T0 10 5 5 3 T1 4 2 2 T2 9 2 7There's one resource type (tape drives, say) with twelve instances, allocated as shown. The threads have the indicated max possible needs and remaining needs. The system shown above is safe. {T1,T0, T2} is a safe sequence - the threads could finish executing in that order, even if all the threads first request all of their remaining needs. However, suppose that, starting from the situation depicted in the table above, T2 requests and is given one more tape drive. Then the state changes to this one:
thread max needs cur alloc needs left free T0 10 5 5 2 T1 4 2 2 T2 9 3 6This system is unsafe. If all the threads request their remaining needs, the system will be deadlocked. It will be possible for the OS to give T1 its remaining needs, and possible for T1 to finish and exit. However, after that there will be only 4 tape drives free, and so both T0 and T2 are set up to wait forever.