120 likes | 200 Vues
Learn about the conditions leading to deadlock in processes and resources, solutions, avoidance strategies, detection, prevention, and recovery methods. Explore deadlock scenarios with code examples and discuss asymmetric solutions.
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