Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε

Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε

Νήματα- Συγχρονισμός Λειτουργικά Συστήματα. Για τη δημιουργία των διαφανειών έχει χρησιμοποιηθεί υλικό από τις διαφάνειες παραδόσεων των Π.Λάμψας & Σ.

Παρόμοιες παρουσιάσεις


Παρουσίαση με θέμα: "Νήματα- Συγχρονισμός Λειτουργικά Συστήματα. Για τη δημιουργία των διαφανειών έχει χρησιμοποιηθεί υλικό από τις διαφάνειες παραδόσεων των Π.Λάμψας & Σ."— Μεταγράφημα παρουσίασης:

1 Νήματα- Συγχρονισμός Λειτουργικά Συστήματα

2 Για τη δημιουργία των διαφανειών έχει χρησιμοποιηθεί υλικό από τις διαφάνειες παραδόσεων των Π.Λάμψας & Σ. Λάλης για το μάθημα Λειτουργικά Συστήματα Παν. Θεσ.

3 Λειτουργικά Συστήματα/ Slide 3 Εισαγωγή * Επισκόπηση * Μοντέλα πολλαπλών νημάτων (Multithreading Models) * Θέματα νημάτων (Threading Issues) * Pthreads και νήματα σε μερικά δημοφιλή ΛΣ

4 Λειτουργικά Συστήματα/ Slide 4 Η Έννοια της Διεργασίας (και) Γιατί οι Διεργασίες δεν είναι Αρκετές * Η διεργασία είναι κυρίως μια λογική έννοια, η οποία στην πράξη υλοποιείται με τον μηχανισμό της διεργασίας σε επίπεδο ΛΣ. Μια λογική διεργασία μπορεί να αντιστοιχεί σε μια (ή περισσότερες) διεργασίες του ΛΣ * Τι γίνεται όμως αν μια λογική διεργασία χρειάζεται να υποστηρίξει «ταυτόχρονη» εκτέλεση κώδικα;

5 Λειτουργικά Συστήματα/ Slide 5 Η Έννοια της Διεργασίας (και) Γιατί οι Διεργασίες δεν είναι Αρκετές * Μπορεί να δημιουργηθούν πολλές διεργασίες (ΛΣ) που συνεργάζονται για τον κοινό σκοπό (της λογικής διεργασίας) * Όμως ακόμα και αν οι διεργασίες δημιουργηθούν έτσι ώστε να επικοινωνούν (αποδοτικά) μέσω κοινής μνήμης, το σύστημα επιβαρύνεται λόγω των επιπρόσθετων εναλλαγών περιβάλλοντος λειτουργίας (context switch) που πραγματοποιούνται

6 Λειτουργικά Συστήματα/ Slide 6 Νήματα * Τα νήματα (νήματα ελέγχου), ονομάζονται και ελαφρές διεργασίες (lightweight processes – LWPs), είναι ξεχωριστές ροές του ίδιου προγράμματος που εκτελούνται μέσα σε μια λογική διεργασία * Τα νήματα μιας διεργασίας ανήκουν πάντα στον ίδιο χρήστη

7 Λειτουργικά Συστήματα/ Slide 7 Νήματα * Λειτουργούν (στην ουσία) όπως και οι διεργασίες, δεν είναι όμως πραγματικά ανεξάρτητες εκτελέσεις, καθώς: n έχουν τα ίδια δικαιώματα πρόσβασης σε πόρους n μοιράζονται τους ίδιους πόρους (δεδομένα, κώδικα, ανοικτά αρχεία, σήματα, … ακόμα και τον χρόνο της ΚΜΕ) n μοιράζονται την ίδια μνήμη!

8 Λειτουργικά Συστήματα/ Slide 8 Thread Switch vs Context Switch * Για κάθε νήμα διατηρείται ξεχωριστή κατάσταση εκτέλεσης, δηλαδή μετρητής προγράμματος, τιμές των καταχωρητών και στοίβα * Η εναλλαγή μεταξύ νημάτων (thread switch) ισοδυναμεί στην πράξη με απλή εναλλαγή κατάστασης ΚΜΕ (register set switch) και όχι με πραγματική εναλλαγή περιβάλλοντος λειτουργίας (context switch) * Κατά το thread switch δεν πραγματοποιούνται λειτουργίες διαχείρισης μνήμης και δικαιωμάτων πρόσβασης, με αποτέλεσμα το thread switch να είναι πολύ πιο γρήγορο από το context switch

9 Λειτουργικά Συστήματα/ Slide 9 Διεργασίες και Νήματα

10 Λειτουργικά Συστήματα/ Slide 10 Πλεονεκτήματα Χρήσης Νημάτων (αντί Συνεργαζομένων Διεργασιών) * Απόκριση / απόδοση συστήματος * Διαμοιρασμός πόρων (Resource Sharing) * Οικονομία πόρων * Εκμετάλλευση αρχιτεκτονικών πολλαπλών επεξεργαστών Πρόβλημα: * Έλεγχος συγχρονισμού (concurrency control problems)

11 Λειτουργικά Συστήματα/ Slide 11 Υλοποίηση Νημάτων σε Επίπεδο Χρήστη (User Threads) * Η διαχείριση των νημάτων γίνεται από βιβλιοθήκες που εκτελούνται σε κατάσταση χρήστη (user mode). Αποφεύγεται η επικοινωνία με το σύστημα/πυρήνα (δεν πραγματοποιούνται κλήσεις συστήματος) * Τα νήματα εκτελούνται μέσα από μια κοινή διεργασία * Ένα νήμα αφήνει την ΚΜΕ με κλήση της ρουτίνας εναλλαγής, με λειτουργία που προκαλεί έμμεσα εναλλαγή ή με την λήξη ενός μετρητή * Συνήθως δεν υποστηρίζεται κατανομή του χρόνου εκτέλεσης της διεργασίας στα διάφορα νήματα που έχει μέσα της * Παραδείγματα: POSIX pthreads, Mach C-threads, Solaris threads

12 Λειτουργικά Συστήματα/ Slide 12 Νήματα σε Επίπεδο Χρήστη (συνέχεια) Πλεονεκτήματα: * Τα νήματα χρήστη εναλλάσσονται (θεωρητικά) γρηγορότερα από τα νήματα πυρήνα. Ωστόσο, στην πράξη, καλές υλοποιήσεις νημάτων σε επίπεδο πυρήνα [Linux] εναλλάσσονται με συναφή απόδοση Μειονεκτήματα: * Ένα νήμα μπορεί να μονοπωλήσει τον χρόνο εκτέλεσης μιας διεργασίας (λιμοκτονία (starvation) των υπολοίπων νημάτων) * Δεν γίνεται εκμετάλλευση της συμμετρικής πολυεπεξεργασίας * Όταν μπλοκαριστεί ένα νήμα μέσα σε κάποια λειτουργία Ι/Ο τότε μπλοκάρονται όλα τα νήματα που εκτελούνται μέσα στην ίδια διεργασία (γιατί το ΛΣ δεν «γνωρίζει» την ύπαρξη τους)

13 Λειτουργικά Συστήματα/ Slide 13 Υλοποίηση Νημάτων σε Επίπεδο Συστήματος/Πυρήνα (Kernel Threads) * Τα νήματα πυρήνα υλοποιούνται στον πυρήνα του ΛΣ, και οι αντίστοιχες βιβλιοθήκες χρησιμοποιούν κλήσεις συστήματος * Σε αυτή την περίπτωση ο πυρήνας χρονοδρομολογεί κάθε νήμα εντός της μονάδας χρόνου που αναλογεί στην διεργασία μέσα στην οποία εκτελούνται τα νήματα * Υπάρχει περισσότερος φόρτος στο σύστημα λόγω της εναλλαγής κατάστασης χρήστη σύστημα (user mode system mode) και την διαχείριση πιο πολύπλοκων περιβαλλόντων, αλλά οι αρχικές μετρήσεις απόδοσης δείχνουν αμελητέα αύξηση στο χρόνο * Παραδείγματα: Windows 95/98/NT/2000, Solaris,Tru64 UNIX, BeOS, Linux

14 Λειτουργικά Συστήματα/ Slide 14 Νήματα σε Επίπεδο Πυρήνα (συνέχεια) Πλεονεκτήματα: * Αποτροπή της μονοπώλησης της μονάδας χρόνου μιας διεργασίας από ένα νήμα (ενώ υπάρχουν και άλλα προς εκτέλεση) * Το μπλοκάρισμα ενός νήματος σε Ι/Ο δεν συνεπάγεται μπλοκάρισμα και των άλλων νημάτων που εκτελούνται μέσα στην ίδια διεργασία * Μια διεργασία μπορεί να εκμεταλλευτεί (πιο εύκολα) τη συμμετρική πολυεπεξεργασία του ΛΣ και να τρέχει γρηγορότερα με κάθε ΚΜΕ που προστίθεται στο σύστημα Μειονεκτήματα: * Ταχύτητα εναλλαγής νημάτων

15 Λειτουργικά Συστήματα/ Slide 15 Μοντέλα Πολλαπλών Νημάτων (Multithreading Models) * Ανάλογα με το αν το ΛΣ υποστηρίζει νήματα σε επίπεδο πυρήνα αλλά και το πως αυτά αντιστοιχίζονται σε νήματα επιπέδου χρήστη, υπάρχουν διάφορες προσεγγίσεις υλοποίησης: n Πολλά σε Ένα (Many-to-One) n Ένα προς Ένα (One-to-One) n Πολλά προς Πολλά (Many-to-Many)

16 Λειτουργικά Συστήματα/ Slide 16 Πολλά σε Ένα (Many-to-One) * Πολλά νήματα επιπέδου χρήστη αντιστοιχούν σε ένα νήμα πυρήνα * Χρησιμοποιείται σε συστήματα που δεν υποστηρίζουν νήματα πυρήνα

17 Λειτουργικά Συστήματα/ Slide 17 Μοντέλο Πολλά σε Ένα

18 Λειτουργικά Συστήματα/ Slide 18 Ένα προς Ένα (One-to-One) * Κάθε νήμα χρήστη αντιστοιχεί σε ένα νήμα πυρήνα * Παραδείγματα: - Windows 95/98/NT/ OS/2

19 Λειτουργικά Συστήματα/ Slide 19 Μοντέλο Ένα προς Ένα

20 Λειτουργικά Συστήματα/ Slide 20 Μοντέλο Πολλά προς Πολλά * Επιτρέπει σε πολλά νήματα χρήστη να αντιστοιχιστούν σε πολλά νήματα πυρήνα * Επιτρέπει στο ΛΣ να δημιουργήσει επαρκή αριθμό νημάτων πυρήνα * Solaris 2 * Windows NT/2000 με το πακέτο ThreadFiber

21 Λειτουργικά Συστήματα/ Slide 21 Μοντέλο Πολλά προς Πολλά (συνέχεια)

22 Λειτουργικά Συστήματα/ Slide 22 Θέματα Νημάτων (Threading Issues) * Σημασιολογία των κλήσεων συστήματος fork() και exec() * Δεξαμενές νημάτων (Thread pools) * Ακύρωση νημάτων (Thread cancellation) * Χειρισμός σημάτων (Signal handling) * Δεδομένα σχετικά με τα νήματα (Thread specific data)

23 Λειτουργικά Συστήματα/ Slide 23 Pthreads (POSIX Threads) * Μια τυποποίηση POSIX (IEEE c) API για δημιουργία και συγχρονισμό νημάτων σε περιβάλλον Unix * To API προσδιορίζει τους τύπους (types), τις επικεφαλίδες των ρουτινών (interfaces), και την συμπεριφορά των ρουτινών της αντίστοιχης βιβλιοθήκης * Η υλοποίηση της βιβλιοθήκης εναπόκειται στο ΛΣ

24 Λειτουργικά Συστήματα/ Slide 24 Νήματα στο Solaris 2

25 Λειτουργικά Συστήματα/ Slide 25 Διεργασίες στο Solaris 2

26 Λειτουργικά Συστήματα/ Slide 26 Νήματα στα Windows 2000 * Υλοποιούν την αντιστοίχηση «Ένα προς Ένα» * Κάθε νήμα περιέχει: n ένα thread id n ένα σύνολο από καταχωρητές (register set) n ξεχωριστές στοίβες για το χρήστη και τον πυρήνα n ιδιωτικό χώρο αποθήκευσης δεδομένων

27 Λειτουργικά Συστήματα/ Slide 27 Νήματα στο Linux (Linux Threads) * To Linux αναφέρεται σε αυτά ως εργασίες (tasks) παρά ως νήματα * Η δημιουργία νημάτων γίνεται μέσω της κλήσης συστήματος clone() * H Clone() επιτρέπει σε μια εργασία παιδί να μοιράζεται το χώρο διευθύνσεων της πατρικής εργασίας (διεργασίας)

28 Λειτουργικά Συστήματα/ Slide 28 Νήματα στην Java * Τα νήματα στη Java μπορούν να δημιουργηθούν μέσω: n Επέκτασης του Thread class n Υλοποίησης της διεπαφής Runnable * Την διαχείριση των νημάτων στη Java αναλαμβάνει η JVM

29 Λειτουργικά Συστήματα/ Slide 29 Κατάσταση Νημάτων στην Java

30 Λειτουργικά Συστήματα/ Slide 30 Νήματα στην Java Δέστε παραδείγματα: Driver.java Driver2.java SleepMessages.java SimpleThreads.java

31 Συγχρονισμός Διεργασιών σε Κοινή Μνήμη (Process Synchronization)

32 Λειτουργικά Συστήματα/ Slide 32 Εισαγωγή * Θεωρητικό υπόβαθρο * Το πρόβλημα του κρίσιμου τμήματος (the critical- section problem) * Υλικό συγχρονισμού * Σηματοφορείς ή σημαφόροι (semaphores) * Κλασικά προβλήματα συγχρονισμού * Κρίσιμες περιοχές (critical regions) * Ελεγκτές/παρακολουθητές (monitors)

33 Λειτουργικά Συστήματα/ Slide 33 Θεωρητικό Υπόβαθρο * Η ταυτόχρονη πρόσβαση σε κοινά δεδομένα μπορεί να οδηγήσει σε ασυνέπεια δεδομένων (data inconsistency) * Το πρόβλημα της συνέπειας υφίσταται στα νήματα και στις διεργασίες(*) με κοινή μνήμη που έχουν ταυτόχρονη πρόσβαση σε όλες τις καθολικές μεταβλητές και τα δυναμικά δεδομένα ενός προγράμματος * Παρόμοιο πρόβλημα αντιμετωπίζει ο κώδικας του συστήματος του οποίου η εκτέλεση μπορεί να διακοπεί από τις ρουτίνες χειρισμού διακοπών (interrupt handlers) που με την σειρά τους μπορεί να κάνουν κλήσεις συστήματος (που και αυτές μπορεί να διακοπούν...) * (*) Σε αυτή την ενότητα χρησιμοποιούμε τον (γενικότερο) όρο διεργασία, ακόμα και όταν αναφερόμαστε σε νήματα

34 Λειτουργικά Συστήματα/ Slide 34 Πρόσβαση σε Κοινή Μεταβλητή (Shared variable) Έστω πως δύο διεργασίες εκτελούν τον παρακάτω κώδικα: int i=0; /* κοινή μεταβλητή */ void body { i++; }  Ποιά η τιμή της μεταβλητής i αφού εκτελεσθούν οι διεργασίες; n Μπορεί να είναι 1 ή 2, δεν το ξέρουμε εκ των προτέρων! n Κάθε εκτέλεση μπορεί να δίνει διαφορετικό αποτέλεσμα!

35 Λειτουργικά Συστήματα/ Slide 35 Γιατί;  Το πρόβλημα είναι πως η εκτέλεση της εντολής i++ δεν είναι (εγγυημένα) ατομική (atomic) δηλαδή χωρίς να υπάρχει πιθανότητα διακοπής της  Η εντολή i++ μεταφράζεται σε γλώσσα μηχανής ως εξής: regX = mem[i_adr]; regX = regX+1; memy[i_adr] = regX; * Η σειριακή εκτέλεση του κώδικα των διεργασιών δίνει διαφορετικό αποτέλεσμα από μια διαπλεκόμενη (interleaved) εκτέλεσή του * Η εκτέλεση εξαρτάται από την (τυχαία) χρονοδρομολόγηση του ΛΣ

36 Λειτουργικά Συστήματα/ Slide 36 Σενάρια Εκτέλεσης Αρχικά η μεταβλητή i έχει την τιμή 0. Σενάριο Α thread 1: reg1 = mem[i_adr]; thread 1: reg1 = reg+1; thread 2: reg2 = mem[i_adr]; thread 2: reg2 = reg2+1; thread 2: mem[i_adr] = reg2; thread 1: mem[i_adr] = reg1; Η μεταβλητή i έχει την τιμή 1 Σενάριο B thread 1: reg1 = mem[i_adr]; thread 1: reg1 = reg+1; thread 1: mem[i_adr] = reg1; thread 2: reg2 = mem[i_adr]; thread 2: reg2 = reg2+1; thread 2: mem[i_adr] = reg2; Η μεταβλητή i έχει την τιμή 2

37 Λειτουργικά Συστήματα/ Slide 37 Κατάσταση Συναγωνισμού (Race Condition) * Κατάσταση Συναγωνισμού: Η κατάσταση όπου πολλές διεργασίες προσπελαύνουν και χειρίζονται ταυτόχρονα κοινά δεδομένα * Η τελική τιμή των κοινών δεδομένων εξαρτάται από το πως θα δρομολογηθεί η επιμέρους εκτέλεσης του κώδικα των διεργασιών * Για την αποτροπή καταστάσεων συναγωνισμού, οι διεργασίες με κοινή μνήμη πρέπει να συγχρονίζονται

38 Λειτουργικά Συστήματα/ Slide 38 Το Πρόβλημα του Κρίσιμου Τμήματος (critical section problem) * Ένας αριθμός από Ν διεργασίες εκτελούνται ταυτόχρονα μεταξύ τους και επιθυμούν να χρησιμοποιήσουν κάποια κοινά δεδομένα * Κάθε διεργασία έχει ένα τμήμα κώδικα που καλείται κρίσιμο τμήμα (critical section), στο οποίο προσπελαύνονται τα κοινά δεδομένα Πρόβλημα: Διασφάλισε ότι όταν μια διεργασία εκτελεί κώδικα στο κρίσιμο τμήμα της, καμία άλλη διεργασία δεν θα να εκτελέσει στο κρίσιμο τμήμα της

39 Λειτουργικά Συστήματα/ Slide 39 Αφηρημένη Δομή των Διεργασιών while (1) { Κανονικός Κώδικας (δεν τίθεται θέμα συγχρονισμού) Κρίσιμο Τμήμα (critical section) Κανονικός Κώδικας (δεν τίθεται θέμα συγχρονισμού) }

40 Λειτουργικά Συστήματα/ Slide 40 Οι 3 Απαιτήσεις της Λύσης του Κρίσιμου Τμήματος 1.Αμοιβαίος αποκλεισμός (mutual exclusion): Αν η μια διεργασία εκτελεί κώδικα στο κρίσιμο τμήμα της, τότε καμία άλλη διεργασία δεν εκτελεί κώδικα στο κρίσιμο τμήμα της 2.Πρόοδος (progress): Αν δεν υπάρχει διεργασία που να βρίσκεται μέσα στο κρίσιμο τμήμα της και υπάρχουν διεργασίες που επιθυμούν να εισέλθουν στο κρίσιμο τμήμα τους, τότε η επιλογή της επόμενης διεργασίας που θα εισέλθει στο κρίσιμο τμήμα της δεν μπορεί να αναβάλλεται επ’ αόριστον

41 Λειτουργικά Συστήματα/ Slide 41 Οι 3 Απαιτήσεις της Λύσης του Κρίσιμου Τμήματος (συνέχεια) 3.Πεπερασμένη Αναμονή (bounded waiting): Πρέπει να υπάρχει ένα όριο στο πλήθος των φορών που επιτρέπεται σε άλλες διεργασίες να εισέλθουν στο κρίσιμο τμήμα τους, αφότου μια διεργασία έχει εκδώσει αίτηση να εισέλθει στο κρίσιμο τμήμα της και μέχρι η αίτηση αυτή να ικανοποιηθεί n Υποθέτουμε ότι κάθε διεργασία εκτελείται με μη μηδενική ταχύτητα n Δεν μπορεί να γίνει καμία υπόθεση η οποία να αφορά τη σχετική ταχύτητα των διαφόρων διεργασιών, ή το πλήθος των επεξεργαστών στους οποίους εκτελούνται οι διεργασίες

42 Λειτουργικά Συστήματα/ Slide 42 Πιο Λεπτομερής Δομή των Διεργασιών while (1) { Κανονικός Κώδικας (δεν τίθεται θέμα συγχρονισμού) Κρίσιμο Τμήμα (critical section) Κανονικός Κώδικας (δεν τίθεται θέμα συγχρονισμού) } Κώδικας Εισόδου (entry code) Κώδικας Εξόδου (exit code)

43 Λειτουργικά Συστήματα/ Slide 43 Αλγόριθμος 1 (δύο Διεργασίες)  Κοινή μεταβλητή turn (η διεργασία P i εισέρχεται στο ΚΤ μόνο όταν turn=i ): shared vars: int turn=0; process body: while (1) { while (turn!=i) {} /* entry code */ do_critical_section(); turn=(i+1)%2; /* exit code */ } * Ικανοποιεί τον αμοιβαίο αποκλεισμό, αλλά όχι την πρόοδο (γιατί;)

44 Λειτουργικά Συστήματα/ Slide 44 Αλγόριθμος 2 (δύο Διεργασίες)  Κοινή μεταβλητή boolean flag[2] (η διεργασία P i εισέρχεται στο ΚΤ μόνο όταν flag[i]= true ): shared vars: boolean flag[2]={false,false}; process body: while (1) { flag[i]=true; /* entry code */ while (flag[(i+1)%2]) {} do_critical_section(); flag[i]=false; /* exit code */ } * Ικανοποιεί τον αμοιβαίο αποκλεισμό, αλλά όχι την πρόοδο (γιατί;)

45 Λειτουργικά Συστήματα/ Slide 45 Αλγόριθμος Paterson (δύο Διεργασίες) * Συνδυασμός των δύο προηγουμένων αλγορίθμων: shared vars: int turn=0; boolean flag[2]={false,false}; process body: while (1) { flag[i]=true; turn=(i+1)%2; /* entry code */ while ( (flag[(i+1)%2]) && (turn=(i+1)%2) ) {} do_critical_section(); flag[i]=false; /* exit code */ } * Ικανοποιεί και τις τρεις απαιτήσεις (γιατί;)

46 Λειτουργικά Συστήματα/ Slide 46 Αλγόριθμός για πολλές Διεργασίες Ο Αλγόριθμος Bakery * Πριν την είσοδό της στο κρίσιμο τμήμα, μια διεργασία P i λαμβάνει έναν αριθμό σειράς t i. Το σύστημα αριθμοδότησης δημιουργεί αριθμούς σειράς με αύξουσα σειρά αρίθμησης, π.χ., 1,2,3,3,3,4,5… * Η διεργασία με τον μικρότερο αριθμό σειράς εισέρχεται στο κρίσιμο τμήμα * Αν οι διεργασίες P i και P j έχουν τον ίδιο αριθμό σειράς, αν i < j, τότε εξυπηρετείται πρώτα η P i, αλλιώς πρώτα η P j * Συμβολισμοί: n (a,b) before (c,d) ((a < c) || ((a = c) && (b < d)) n max (a 0,…, a n-1 ) = k, k  a i για i = 0,…, n – 1

47 Λειτουργικά Συστήματα/ Slide 47 Ο Αλγόριθμος Bakery (συνέχεια) shared vars: boolean choosing[n]={false,…,false}; int t[n]={0,…,0}; process body: while (1) { choosing[i] = true; t[i] = max(t[0],t[1],…, t[n-1])+1; choosing[i] = false; for (j=0; j

48 Λειτουργικά Συστήματα/ Slide 48 Υλικό Συγχρονισμού (Synchronization Hardware)  Μερικοί επεξεργαστές υποστηρίζουν την εξής εντολή TestAndSet για τον ατομικό έλεγχο και αλλαγή μιας θέσης μνήμης (μεταβλητής) * Η συμβολική υλοποίηση της εντολής δίνεται ως εξής: boolean TestAndSet(boolean *target) { boolean value_read = *target; *target = true; return value_read; } * Η εντολή εκτελείται χωρίς διακοπή (εγγυημένα)

49 Λειτουργικά Συστήματα/ Slide 49 Αλγόριθμος Κρίσιμου Τμήματος με Χρήση της TestandSet shared vars: boolean lock=false; process body: while (1) { while (TestAndSet(&lock)) {} do_critical_section(); lock = false; }

50 Λειτουργικά Συστήματα/ Slide 50 Υλικό Συγχρονισμού (συνέχεια) * Εξατομικευμένη εναλλαγή δύο μεταβλητών void Swap(boolean *a, boolean *b) { boolean tmp; tmp = *a; *a = *b; *b = tmp; }

51 Λειτουργικά Συστήματα/ Slide 51 Αλγόριθμος Κρίσιμου Τμήματος με Χρήση της Swap shared vars: boolean lock=false; process body: boolean key; while (1) { key=true; do {Swap(&lock,&key);} while (key); do_critical_section(); lock = false; }

52 Λειτουργικά Συστήματα/ Slide 52 Σημαφόροι ή Σηματοφορείς (Semaphores) * Εργαλείο συγχρονισμού που δεν απαιτεί ενεργό αναμονή (busy waiting) της διεργασίας, εκτελώντας κάποιες εντολές σε βρόγχο * Μια μεταβλητή τύπου s σηματοφορέα μπορεί να προσπελαστεί μέσω δύο ατομικών πράξεων wait (ή down) και signal (ή up), που μπορεί να θεωρηθεί πως υλοποιούνται ως εξής: void wait(int *s) { while (*s<=0) {} *s--; } void signal(int *s) { *s++; }

53 Λειτουργικά Συστήματα/ Slide 53 Υλοποίηση Κρίσιμου Τμήματος για n Διεργασίες με Σημαφόρους shared vars: semaphore s=1; process body: while (1) { wait(s); do_critical_section(); signal(s); }

54 Λειτουργικά Συστήματα/ Slide 54 Υλοποίηση Σημαφόρου typedef struct { int sval; /* value of semaphore */ struct procQ pq;/* queue of waiting processes */ } semaphore; void init(semaphore *s, int val) { s->sval=val; initQ(s->pq); }

55 Λειτουργικά Συστήματα/ Slide 55 Υλοποίηση Σημαφόρου (συνέχεια) void wait(semaphore *s) { s->sval--; if (s->sval<0) { addQ(s->pq,thisProcess()); suspend(); } void signal(semaphore *s) { s->sval++; if (s->sval<=0) { resume(rmvQ(s->pq)); }

56 Λειτουργικά Συστήματα/ Slide 56 Η Σημαφόρος ως ένα Γενικό Εργαλείο Συγχρονισμού Διεργασία P i Διεργασία P j… A wait(flag) signal(flag) B…  Χρήση της σημαφόρου flag με αρχική τιμή 0 * Εκτέλεση του B στην P j μόνο αφού εκτελεστεί το A στην P i

57 Λειτουργικά Συστήματα/ Slide 57 Τύποι Σημαφόρων * Γενική σημαφόρος (ή σημαφόρος μετρητής) (general or counting semaphore) – μπορεί να έχει μια οποιαδήποτε ακέραια τιμή * Δυαδική σημαφόρος (binary semaphore) – μπορεί να παίρνει τιμές μόνο μεταξύ 0 και 1, κάτι που μπορεί να σημαίνει ευκολότερη υλοποίηση * Μια γενική σημαφόρος μπορεί να υλοποιηθεί με χρήση δυαδικών σημαφόρων

58 Λειτουργικά Συστήματα/ Slide 58 Κλασικά Προβλήματα Συγχρονισμού * Το πρόβλημα της αποθήκης πεπερασμένης χωρητικότητας (bounded-buffer problem) * Το πρόβλημα αναγνωστών και εγγραφέων (readers and writers problem) * Το πρόβλημα των συνδαιτυμόνων φιλοσόφων (dining philosophers problem)

59 Λειτουργικά Συστήματα/ Slide 59 Αποθήκη Πεπερασμένης Χωρητικότητας Κοινά δεδομένα: semaphore mutex,full,empty; Αρχικοποίηση: init(&mutex,1); init(&empty,n); init(&full,0);

60 Λειτουργικά Συστήματα/ Slide 60 Διεργασία Παραγωγός (producer) while (1) { … παραγωγή αντικειμένου item wait(&empty); wait(&mutex); προσθήκη αντικειμένου item στην αποθήκευση signal(&mutex); signal(&full); … }

61 Λειτουργικά Συστήματα/ Slide 61 Διεργασία Καταναλωτής (consumer) while (1) { … wait(&full); wait(&mutex); απομάκρυνση αντικειμένου item από την αποθήκευση signal(&mutex); signal(&empty); κατανάλωση αντικειμένου item … }

62 Λειτουργικά Συστήματα/ Slide 62 Αναγνώστες και Εγγραφείς Κοινά δεδομένα: semaphore mutex,write; int readers; Αρχικοποίηση: init(&mutex,1); init(&write,1); readers=0;

63 Λειτουργικά Συστήματα/ Slide 63 Διεργασία Εγγραφέας while (1) { … wait(&write); γράψιμο δεδομένων signal(&write); … }

64 Λειτουργικά Συστήματα/ Slide 64 Διεργασία Αναγνώστης while (1) { … wait(&mutex); readers++; if (readers==1) {wait(&write);} signal(&mutex); διάβασμα δεδομένων wait(&mutex); readers--; if (readers==0) {signal(&write);} signal(&mutex); … }

65 Λειτουργικά Συστήματα/ Slide 65 Οι Συνδαιτυμόνες Φιλόσοφοι Κοινά δεδομένα: semaphore fork[n]; Αρχικοποίηση: init(&fork[0],1); init(&fork[1],1); … init(&fork[n-1],1);

66 Λειτουργικά Συστήματα/ Slide 66 Ο Φιλόσοφος i while (1) { … wait(&fork[i]); wait(&fork[(i+1)%n); επιτέλους τρώμε! signal(&fork[i]); signal(&fork[(i+1)%n]); ας σκεφτούμε λιγάκι … } * Υπάρχει περίπτωση ο ένας φιλόσοφος να περιμένει τον άλλο σε κύκλο;

67 Λειτουργικά Συστήματα/ Slide 67 Αδιέξοδο και Λιμοκτονία (Deadlock and Starvation) * Αδιέξοδο – δύο ή περισσότερες διεργασίες περιμένουν απεριόριστα για ένα γεγονός που μπορεί να προκληθεί μόνο από μια από τις δυο * Έστω S και Q δύο σημαφόροι με αρχική τιμή 1 P 0 P 1 wait(S);wait(Q); wait(Q);wait(S);   signal(S);signal(Q); signal(Q)signal(S); * Λιμοκτονία – απεριόριστη αναμονή. Μια διεργασία μπορεί να μην φύγει από την ουρά της σημαφόρου στην οποία έχει ανασταλεί

68 Λειτουργικά Συστήματα/ Slide 68 Κρίσιμες Περιοχές (Critical Regions) * Δομή υψηλού επιπέδου για την υποστήριξη του συγχρονισμού κρίσιμων τμημάτων, ως εξής:  Μια κοινή μεταβλητή v τύπου T ορίζεται ως: T (shared) v;  Η v μπορεί να προσπελαστεί μόνο μέσω της εντολής region : region v when B do S; όπου η διεργασία ελέγχει την συνθήκη B και αν είναι αληθής, τότε εκτελεί την ομάδα εντολών S, διαφορετικά αναστέλλεται μέχρι η συνθήκη B να γίνει αληθής.  Τόσο ο έλεγχος της συνθήκης B όσο και η εκτέλεση της ομάδας εντολών S γίνεται ατομικά (το σύστημα εγγυάται πως δεν παρεμβάλλονται άλλες διεργασίες σε αυτή την περιοχή).

69 Λειτουργικά Συστήματα/ Slide 69 Αποθήκη Πεπερασμένης Χωρητικότητας με Κρίσιμες Περιοχές typedef struct { item slots[n]; int in,out,cnt; } buffer; buffer (shared) b; b.cnt=0; b.in=b.out=0; slots[0] slots[n-1] direction of in, out

70 Λειτουργικά Συστήματα/ Slide 70 Αποθήκη Πεπερασμένης Χωρητικότητας (συνέχεια) Διεργασία Παραγωγός while (1) { … item=produce(); region b when (b.cnt0){ item=b.slots[b.out]; b.out=(b.out+1)%n; b.cnt--; } consume(item); … }

71 Λειτουργικά Συστήματα/ Slide 71 Ελεγκτές/Παρακολουθητές (Monitors) * Δομή υψηλού επιπέδου που επιτρέπει την ασφαλή πρόσβαση ενός αφηρημένου τύπου δεδομένων μεταξύ ταυτόχρονων διεργασιών monitor monitor-name { δηλώσεις κοινών μεταβλητών procedure P1 (…) {…} procedure P2 (…) {…} procedure Pn (…) {…} { κώδικας αρχικοποίησης }  Οι ρουτίνες πρόσβασης Pi εκτελούνται συγχρονισμένα, με εγγυημένο τον αμοιβαίο αποκλεισμό ανάμεσα σε διεργασίες

72 Λειτουργικά Συστήματα/ Slide 72 Ελεγκτές/Παρακολουθητές (συνέχεια)  Για να επιτραπεί σε μια διεργασία να περιμένει μέσα σε έναν ελεγκτή, πρέπει να δηλωθεί αντίστοιχη μεταβλητή συνθήκης (condition variable): condition x;  Μπορεί να χρησιμοποιηθεί μόνο με τις λειτουργίες wait και signal Η λειτουργία x.wait() σημαίνει ότι η διεργασία αναστέλλεται Η λειτουργία x.signal() εκκινεί (μόνο) μια από τις διεργασίες που έχουν ανασταλεί, αν υπάρχει (διαφορετικά δεν κάνει τίποτα) Η λειτουργία x.signalAll() εκκινεί όλες τις διεργασίες (αν υπάρχουν) που έχουν ανασταλεί μέσω της μεταβλητής x

73 Λειτουργικά Συστήματα/ Slide 73 Αναμονή με Προτεραιότητες  Αναμονή υπό συνθήκη (conditional-wait): x.wait(c); c – ακέραιος που ελέγχεται όταν εκτελείται η λειτουργία wait Η τιμή του c (αριθμός προτεραιότητας) αποθηκεύεται με το όνομα της διεργασίας που ανεστάλη Η εκτέλεση της x.signal, ενεργοποιεί τη διεργασία με τη μικρότερη προτεραιότητα

74 Λειτουργικά Συστήματα/ Slide 74 Σχηματική Θεώρηση ενός Ελεγκτή

75 Λειτουργικά Συστήματα/ Slide 75 Ελεγκτής με Μεταβλητές Συνθήκης

76 Λειτουργικά Συστήματα/ Slide 76 Συνδαιτυμόνες Φιλόσοφοι με Ελεγκτή monitor dining_phils { enum {thinking,hungry,eating} state[n]; condition self[n]; void pickup(int i); void putdown(int i); void test(int i); void init() { int i; for (i=0; i<5; i++) {state[i] = thinking;} }

77 Λειτουργικά Συστήματα/ Slide 77 Συνδαιτυμόνες Φιλόσοφοι (συνέχεια) void pickup(int i) { state[i] = hungry; test(i); if (state[i] != eating) { self[i].wait(); } void putdown(int i) { state[i] = thinking; test((i+n-1)%n); /* test left */ test((i+1)%n); /* test right */ }

78 Λειτουργικά Συστήματα/ Slide 78 Συνδαιτυμόνες Φιλόσοφοι (συνέχεια) void test(int i) { if ( (state[i] == hungry) && (state[(i+n-1)%5] != eating) && (state[(i+1)%n] != eating) ) { state[i] = eating; self[i].signal(); }

79 Λειτουργικά Συστήματα/ Slide 79 Υλοποίηση Ελεγκτών με Σημαφόρους * Για κάθε ελεγκτή, καθολικές μεταβλητές: semaphore mutex,next; int next-count;  Επιπλέον, για κάθε μεταβλητή συνθήκης, μεταβλητές: semaphore x-sem; int x-count; * Αρχικοποίηση του ελεγκτή: init(&mutex,1); init(&next,0); next-count=0;  Και αρχικοποίηση για κάθε μεταβλητή συνθήκης: init(&x-sem); x-count=0;

80 Λειτουργικά Συστήματα/ Slide 80 Υλοποίηση Ελεγκτών με Σημαφόρους (συνέχεια) * Για κάθε ρουτίνα πρόσβασης Pi, το σώμα της αντικαθίσταται με : procedure Pi (…) { wait(&mutex); κυρίως σώμα της Pi if (next-count > 0) {signal(&next);} else {signal(&mutex);} }

81 Λειτουργικά Συστήματα/ Slide 81 Υλοποίηση Ελεγκτών με Σημαφόρους (συνέχεια)  Η λειτουργία x.wait() μπορεί να υλοποιηθεί ως εξής: x-count++; if (next-count > 0) { signal(&next); } else { signal(&mutex); } wait(&x-sem); x-count--;

82 Λειτουργικά Συστήματα/ Slide 82 Υλοποίηση Ελεγκτών με Σημαφόρους (συνέχεια)  Η λειτουργία x.signal() μπορεί να υλοποιηθεί ως εξής: if (x-count > 0) { next-count++; signal(&x-sem); wait(&next); next-count--; }

83 Λειτουργικά Συστήματα/ Slide 83 Υλοποίηση Ελεγκτών με Σημαφόρους (συνέχεια)  Η λειτουργία x.signalAll() μπορεί να υλοποιηθεί ως εξής: if (x-count > 0) { next-count++; for (c=x-count; c > 0; c--) { signal(&x-sem); } wait(&next); next-count--; }

84 Λειτουργικά Συστήματα/ Slide 84 Συγχρονισμός στην Java * Synchronized, wait/notify/notifyAll * Atomic objects & locks Παραδείγματα: AtomicCounter.java SyncronizedCounter.java Drop.java,Producer.java,Consumer.java,ProducerConsu merExample.java Safelock.java


Κατέβασμα ppt "Νήματα- Συγχρονισμός Λειτουργικά Συστήματα. Για τη δημιουργία των διαφανειών έχει χρησιμοποιηθεί υλικό από τις διαφάνειες παραδόσεων των Π.Λάμψας & Σ."

Παρόμοιες παρουσιάσεις


Διαφημίσεις Google