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

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

Λειτουργικά Συστήματα

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


Παρουσίαση με θέμα: "Λειτουργικά Συστήματα"— Μεταγράφημα παρουσίασης:

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

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

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

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

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

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

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

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

9 Διεργασίες και Νήματα

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

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

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

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

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

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

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

17 Μοντέλο Πολλά σε Ένα

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

19 Μοντέλο Ένα προς Ένα

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

21 Μοντέλο Πολλά προς Πολλά (συνέχεια)

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

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

24 Νήματα στο Solaris 2

25 Διεργασίες στο Solaris 2

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

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

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

29 Κατάσταση Νημάτων στην Java

30 Νήματα στην Java Δέστε παραδείγματα: Driver.java Driver2.java
SleepMessages.java SimpleThreads.java

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

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

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

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

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

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 Κατάσταση Συναγωνισμού (Race Condition)
Κατάσταση Συναγωνισμού: Η κατάσταση όπου πολλές διεργασίες προσπελαύνουν και χειρίζονται ταυτόχρονα κοινά δεδομένα Η τελική τιμή των κοινών δεδομένων εξαρτάται από το πως θα δρομολογηθεί η επιμέρους εκτέλεσης του κώδικα των διεργασιών Για την αποτροπή καταστάσεων συναγωνισμού, οι διεργασίες με κοινή μνήμη πρέπει να συγχρονίζονται

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

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

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

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

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

43 Αλγόριθμος 1 (δύο Διεργασίες)
Κοινή μεταβλητή turn (η διεργασία Pi εισέρχεται στο ΚΤ μόνο όταν 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 Αλγόριθμος 2 (δύο Διεργασίες)
Κοινή μεταβλητή boolean flag[2] (η διεργασία Pi εισέρχεται στο ΚΤ μόνο όταν 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 Αλγόριθμος 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 Αλγόριθμός για πολλές Διεργασίες Ο Αλγόριθμος Bakery
Πριν την είσοδό της στο κρίσιμο τμήμα, μια διεργασία Pi λαμβάνει έναν αριθμό σειράς ti. Το σύστημα αριθμοδότησης δημιουργεί αριθμούς σειράς με αύξουσα σειρά αρίθμησης, π.χ., 1,2,3,3,3,4,5… Η διεργασία με τον μικρότερο αριθμό σειράς εισέρχεται στο κρίσιμο τμήμα Αν οι διεργασίες Pi και Pj έχουν τον ίδιο αριθμό σειράς, αν i < j, τότε εξυπηρετείται πρώτα η Pi, αλλιώς πρώτα η Pj Συμβολισμοί: (a,b) before (c,d) <=> ((a < c) || ((a = c) && (b < d)) max (a0,…, an-1) = k, k  ai για i = 0,…, n – 1

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<n; j++) { while (choosing[j]) {} while ((t[j]!=0) && (t[j],j) before (t[i],i)) {} } do_critical_section(); t[i] = 0; Παραλαβή αριθμού σειράς Έλεγχος προτεραιότητας

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

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

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

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

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

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 Υλοποίηση Σημαφόρου (συνέχεια)
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 Η Σημαφόρος ως ένα Γενικό Εργαλείο Συγχρονισμού
Διεργασία Pi Διεργασία Pj … … A wait(flag) signal(flag) B Χρήση της σημαφόρου flag με αρχική τιμή 0 Εκτέλεση του B στην Pj μόνο αφού εκτελεστεί το A στην Pi

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

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

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

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

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

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

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

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

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

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

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

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

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 Αποθήκη Πεπερασμένης Χωρητικότητας (συνέχεια)
Διεργασία Παραγωγός while (1) { item=produce(); region b when (b.cnt<n){ b.slots[b.in]=item; b.in=(b.in+1)%n; b.cnt++; } Διεργασία Καταναλωτής while (1) { region b when (b.cnt>0){ item=b.slots[b.out]; b.out=(b.out+1)%n; b.cnt--; } consume(item);

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

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

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

74 Σχηματική Θεώρηση ενός Ελεγκτή

75 Ελεγκτής με Μεταβλητές Συνθήκης

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

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

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

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

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


Κατέβασμα ppt "Λειτουργικά Συστήματα"

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


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