120 likes | 187 Views
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.
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