ΕΘΝΙΚΟ ΚΑΙ ΚΑΠΟΔΙΣΤΡΙΑΚΟ ΠΑΝΕΠΙΣΤΗΜΙΟ ΑΘΗΝΩΝ ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ & ΤΗΛΕΠΙΚΟΙΝΩΝΙΩΝ ΧΕΙΜΕΡΙΝΟ ΕΞΑΜΗΝΟ ΜΑΘΗΜΑ: ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ ΔΙΑΧΕΙΡΙΣΗ ΑΔΙΕΞΟΔΩΝ (DEADLOCKS) Γενικά, για τη διαχείριση των αδιεξόδων υιοθετούνται mutexes ώστε να αποτρέψουν πολλαπλά νήματα να προσπελάσουν την κρίσιμη περιοχή τους την ίδια στογμή. Κάποιες φορές όταν κλειδώνουμε ένα mutex πολλαπλά νήματα κρατούν το κλείδωμα με αποτέλεσμα να αποκλείονται αμοιβαία από την κρίσιμη περιοχή τους. Υπάρχουν τέσσερις απαιτήσεις για ένα αδιέξοδο: Mutual exclusion Hold and wait No preemption Circular wait Ένα αδιέξοδο απαιτεί και τις τέσσερις συνθήκες οπότε για να το αποτρέψουμε μπορούμε να αποτρέψουμε οποιαδήποτε από τις τέσσερις συνθήκες. Μια λύση είναι να κλειδώνουμε τους mutexes σε μια σειρά ώστε να αποφεύγουμε την κυκλική αναμονή. Το ακόλουθο παράδειγμα αναδεικνύει το πως μπορει να συμβεί ένα αδιέξοδο. Ο επόμενος κώδικας αναδεικνύει μια συμπεριφορά που εξαρτάται στο περιβάλλον εκτέλεσης και στον scheduler. Όμως με συγχρονισμό θα πέσει σε αδιέξοδο όταν εκτελεστούν τα νήματα thr1, thr2 όπου το thr1 προσπαθεί να κλειδώσει τον mutex ba2 και το thr2 προσπαθεί να κλειδώσει τον mutex ba1 στη συνάρτηση deposit(). Code 1 typedef struct int balance; pthread_mutex_t balance_mutex;
bank_account; typedef struct bank_account *from; bank_account *to; int amount; deposit_thr_args; void create_bank_account(bank_account **ba, int initial_amount) int result; bank_account *nba = malloc(sizeof(bank_account)); if (nba == NULL) nba->balance = initial_amount; result = pthread_mutex_init(&nba->balance_mutex, NULL); if (result) *ba = nba; void *deposit(void *ptr) int result; deposit_thr_args *args = (deposit_thr_args *)ptr; if ((result = pthread_mutex_lock(&(args->from->balance_mutex)))!= 0) /* Not enough balance to transfer */ if (args->from->balance < args->amount) if ((result = pthread_mutex_unlock(&(args->from->balance_mutex)))!= 0) return NULL;
if ((result = pthread_mutex_lock(&(args->to->balance_mutex)))!= 0) args->from->balance -= args->amount; args->to->balance += args->amount; if ((result = pthread_mutex_unlock(&(args->from->balance_mutex)))!= 0) if ((result = pthread_mutex_unlock(&(args->to->balance_mutex)))!= 0) free(ptr); return NULL; int main(void) pthread_t thr1, thr2; int result; bank_account *ba1; bank_account *ba2; create_bank_account(&ba1, 1000); create_bank_account(&ba2, 1000); deposit_thr_args *arg1 = malloc(sizeof(deposit_thr_args)); if (arg1 == NULL) deposit_thr_args *arg2 = malloc(sizeof(deposit_thr_args)); if (arg2 == NULL)
arg1->from = ba1; arg1->to = ba2; arg1->amount = 100; arg2->from = ba2; arg2->to = ba1; arg2->amount = 100; /* Perform the deposits */ if ((result = pthread_create(&thr1, NULL, deposit, (void *)arg1))!= 0) if ((result = pthread_create(&thr2, NULL, deposit, (void *)arg2))!= 0) pthread_exit(null); return 0; Ο επόμενος κώδικας δείχνει τη σώστη λύση όπου υιοθετείται μια σειρά κλειδώματος των mutexes μέσα στη συνάρτηση. Κάθε νήμα κλειδώνει με βάση το bank_account ID που ορίζεται στην αρχικοποίηση του struct. Ο κώδικας αποτρέπει την κυκλική αναμονή. Code 2 #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h> typedef struct int balance; pthread_mutex_t balance_mutex; unsigned int id; /* Should never be changed after initialized */ bank_account; typedef struct bank_account *from; bank_account *to;
int amount; deposit_thr_args; unsigned int global_id = 1; void create_bank_account(bank_account **ba, int initial_amount) int result; bank_account *nba = malloc(sizeof(bank_account)); if (nba == NULL) nba->balance = initial_amount; result = pthread_mutex_init(&nba->balance_mutex, NULL); if (result!= 0) nba->id = global_id++; *ba = nba; void *deposit(void *ptr) deposit_thr_args *args = (deposit_thr_args *)ptr; int result; if (args->from->id == args->to->id) return; /* Ensure proper ordering for locking */ if (args->from->id < args->to->id) if ((result = pthread_mutex_lock(&(args->from->balance_mutex)))!= 0) if ((result = pthread_mutex_lock(&(args->to->balance_mutex)))!= 0) else if ((result = pthread_mutex_lock(&(args->to->balance_mutex)))!= 0)
if ((result = pthread_mutex_lock(&(args->from->balance_mutex)))!= 0) /* Not enough balance to transfer */ if (args->from->balance < args->amount) if ((result = pthread_mutex_unlock(&(args->from->balance_mutex)))!= 0) if ((result = pthread_mutex_unlock(&(args->to->balance_mutex)))!= 0) return; args->from->balance -= args->amount; args->to->balance += args->amount; if ((result = pthread_mutex_unlock(&(args->from->balance_mutex)))!= 0) if ((result = pthread_mutex_unlock(&(args->to->balance_mutex)))!= 0) free(ptr); return; Code 3 #include <stdio.h> #include <pthread.h> #include <stdlib.h> pthread_mutex_t read_mutex; pthread_mutex_t write_mutex;
void * write(void *temp) char *ret; FILE *file1; char *str; pthread_mutex_lock(&write_mutex); sleep(5); pthread_mutex_lock(&read_mutex); printf("\nfile locked, please enter the message \n"); str=(char *)malloc(10*sizeof(char)); file1=fopen("temp","w"); scanf("%s",str); fprintf(file1,"%s",str); fclose(file1); pthread_mutex_unlock(&read_mutex); pthread_mutex_unlock(&write_mutex); printf("\nunlocked the file you can read it now \n"); return ret; void * read(void *temp) char *ret; FILE *file1; char *str; pthread_mutex_lock(&read_mutex); sleep(5); pthread_mutex_lock(&write_mutex); printf("\n Opening file \n"); file1=fopen("temp","r"); str=(char *)malloc(10*sizeof(char)); fscanf(file1,"%s",str); printf("\n Message from file is %s \n",str); fclose(file1); pthread_mutex_unlock(&write_mutex); pthread_mutex_unlock(&read_mutex); return ret;
main() pthread_t thread_id,thread_id1; pthread_attr_t attr; int ret; void *res; ret=pthread_create(&thread_id,null,&write,null); ret=pthread_create(&thread_id1,null,&read,null); printf("\n Created thread"); pthread_join(thread_id,&res); pthread_join(thread_id1,&res); Code 4 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; // These two functions will run concurrently. void* print_i(void *ptr) pthread_mutex_lock(&mutex1); pthread_mutex_lock(&mutex2); printf("i am in i"); pthread_mutex_unlock(&mutex2); pthread_mutex_unlock(&mutex1); void* print_j(void *ptr) pthread_mutex_lock(&mutex2); pthread_mutex_lock(&mutex1); printf("i am in j"); pthread_mutex_unlock(&mutex1); pthread_mutex_unlock(&mutex2);
int main() pthread_t t1, t2; int iret1 = pthread_create(&t1, NULL, print_i, NULL); int iret2 = pthread_create(&t2, NULL, print_j, NULL); while(1) exit(0); //never reached. Ο επόμενος κώδικας μπορεί να αναγνωρίσει πιθανά αδιέξοδα: Code 5 #include <stdio.h> void main() int allocated[15][15],max[15][15],need[15][15],avail[15],tres[15],work[15],flag[15]; int pno,rno,i,j,prc,count,t,total; count=0; printf("\n Enter number of process: "); scanf("%d",&pno); printf("\n Enter number of resources: "); scanf("%d",&rno); for(i=1;i<=pno;i++) flag[i]=0; printf("\n Enter total numbers of each resources: "); for(i=1;i<= rno;i++) scanf("%d",&tres[i]); printf("\n Enter Max resources for each process: "); for(i=1;i<= pno;i++) printf("\n for process %d:",i); for(j=1;j<= rno;j++) scanf("%d",&max[i][j]); printf("\n Enter allocated resources for each process: "); for(i=1;i<= pno;i++)
printf("\n for process %d:",i); for(j=1;j<= rno;j++) scanf("%d",&allocated[i][j]); printf("\n available resources: \n"); for(j=1;j<= rno;j++) avail[j]=0; total=0; for(i=1;i<= pno;i++) total+=allocated[i][j]; avail[j]=tres[j]-total; work[j]=avail[j]; printf(" %d \t",work[j]); do for(i=1;i<= pno;i++) for(j=1;j<=rno;j++) need[i][j]=max[i][j]-allocated[i][j]; printf("\n Allocated matrix Max need"); for(i=1;i<= pno;i++) printf("\n"); for(j=1;j<=rno;j++) printf("%4d",allocated[i][j]); printf(" "); for(j=1;j<=rno;j++)
printf("%4d",max[i][j]); printf(" "); for(j=1;j<=rno;j++) printf("%4d",need[i][j]); prc=0; for(i=1;i<= pno;i++) if(flag[i]==0) prc=i; for(j=1;j<= rno;j++) if(work[j]< need[i][j]) prc=0; break; if(prc!=0) break; if(prc!=0) printf("\n Process %d completed",i); count++; printf("\n Available matrix:"); for(j=1;j<= rno;j++) work[j]+=allocated[prc][j]; allocated[prc][j]=0; max[prc][j]=0; flag[prc]=1;
printf(" %d",work[j]); while(count!=pno&&prc!=0); if(count==pno) printf("\nthe system is in a safe state!!"); else printf("\nthe system is in an unsafe state!!");