120 likes | 274 Vues
This guide explores the phenomenon of deadlocks in operating systems, where processes are stuck waiting for resources held by each other. We discuss the necessary conditions for deadlock, including mutual exclusion, hold and wait, no preemption, and circular wait. Solutions such as deadlock detection, prevention strategies, and avoidance techniques are examined in detail. The interplay of semaphore usage in classic problems like the dining philosophers enhances understanding. By addressing these challenges, programmers can effectively manage resource allocation and minimize deadlock occurrences.
E N D
Operating Systems 6 - deadlock PIETER HARTEL
Deadlock: Each process in a set is waiting for an event that only another can cause • Conditions on processes and resources • Mutual exclusion • Hold and wait • No preemption • Circular wait • Road crossing • Resources? • Solutions?
Strategies • Ignore the problem and it might never happen (Linux?) • Detect when deadlocks occur and then take action • Avoid deadlock by making careful decisions about resource allocation • Prevent deadlock by negating one of the conditions
Avoidance: steer around unsafe states (pros & cons?) • Joint process diagram
Detection & Recovery (pros & cons?) • Detection: • U[P0] = 0 => P0 is not deadlocked • T = A • Q[P1] ≤ T =>P1 is not deadlocked • T’=T+U[P1] • Q[P2] > T’ => P2 is deadlocked • Recovery • Kill P2 • Rollback P2 to pre-defined checkpoint • Pre-empt P2 Q = reQuest; U = Usage R = Resources; A = Available T = Temporary
bool greater(int X[],int Y[]) { for(int j=0;j<R;j++) if(X[j]>Y[j]) return True ; return False ; } #define copy(X,Y) for(int j=0;j<R;j++) X[j]=Y[j]; #define add(X,Y) for(int j=0;j<R;j++) X[j]=X[j]+Y[j]; intmain() { int Temp[R], Zero[R] = {0} ; copy(Temp,Available) ; for(int p=0; p<P; p++) { if(greater(Usage[p],Zero)) { if(greater(reQuest[p],Temp)) { printf("deadlock %d\n",p) ; } else { add(Temp,Usage[p]) ; } } } return 0; } Detect.c • gcc –std=c99 Detect.c • ./a.out • Simplified (why?)
Prevention: Attack one of the four conditions • Mutual exclusion must be permitted • Hold and wait: request all your resources at once. (pros & cons?) • No pre-emption: release & re-request or pre-empt holder (idem?) • Circular wait: order the resource types: • suppose resource R1 precedes R2 then • process P1 may request R1, and then R2, but • process P2 may not request R2 and then R1 P1 requests R2 P2 holds R2
Dining Philosophers • Eating requires left and right fork • Forks cannot be shared simultaneously • No deadlock • No individual starvation • Efficient when there is no contention
#define N 5 #define P 3 sem_t Room; sem_t Fork[P]; void *tphilosopher(void *ptr) { inti, k = *((int *) ptr); for(i = 1; i <= N; i++) { printf("%*cThink %d %d\n", k*4, ' ', k, i); sem_wait(&Room) ; sem_wait(&Fork[k]) ; sem_wait(&Fork[(k+1) % P]) ; printf("%*cEat %d %d\n", k*4, ' ', k, i); sem_post(&Fork[k]) ; sem_post(&Fork[(k+1) % P]) ; sem_post(&Room) ; } pthread_exit(0); } With sempahores • Output? • Initialise semaphores: • Room? • Fork[i]? • gcc Philosophers.c -lpthread • ./a.out
Exercise: prove that no fork is ever held by two philosophers • Let #Pk be the number of philosophers holding Fork k. Then: • Fork(k) + #Pk= 1 (Eat is the critical section, see slide 12, chap 5) • Fork(k) ≥ 0 (semaphore invariant) • Hence #Pk≤ 1 printf("Think\n"); sem_wait(&Room) ; sem_wait(&Fork[k]) ; sem_wait(&Fork[(k+1) % P]) ; printf("Eat\n"); sem_post(&Fork[k]) ; sem_post(&Fork[(k+1) % P]) ; sem_post(&Room) ;
#define N 5 #define P 3 sem_t Fork[P]; void *tphilosopher(void *ptr) { inti, k = *((int *) ptr); for(i = 1; i <= N; i++) { printf("%*cThink %d %d\n", k*4, ' ', k, i); if( k == P-1 ) { sem_wait(&Fork[(k+1) % P]) ; sem_wait(&Fork[k]) ; } else { sem_wait(&Fork[k]) ; sem_wait(&Fork[(k+1) % P]) ; } printf("%*cEat %d %d\n", k*4, ' ', k, i); sem_post(&Fork[k]) ; sem_post(&Fork[(k+1) % P]) ; } pthread_exit(0); } Asymmetric • Output? • gccAsymmetric.c -lpthread • ./a.out
Summary • A deadlock permanently blocks certain processes • Starvation always favour others over certain processes • Showing the existing of these problems is easier than the absence • Linux provides the tools but leaves the consequences for the programmer