Αμοιβαίος αποκλεισμός με κοινή μνήμη. Ταυτόχρονος Προγραμματισμός 1

Σχετικά έγγραφα
Αμοιβαίος αποκλεισμός με κοινή μνήμη. Ταυτόχρονος Προγραμματισμός 1

Αμοιβαίος αποκλεισμός με κοινή μνήμη. Ταυτόχρονος Προγραμματισμός 1

Προβλήματα ταυτόχρονης εκτέλεσης (για νήματα με κοινή μνήμη)

Προβλήματα ταυτόχρονης εκτέλεσης (για νήματα με κοινή μνήμη)

Προβλήματα ταυτόχρονης εκτέλεσης (για νήματα με κοινή μνήμη)

Προβλήματα ταυτόχρονης εκτέλεσης (για νήματα με κοινή μνήμη)

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

Ελεγκτές/Παρακολουθητές (Monitors) Ταυτόχρονος Προγραμματισμός 1

Κρίσιμη Περιοχή Υπό Συνθήκη (Conditional Critical Regions) Ταυτόχρονος Προγραμματισμός 1

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

Σηματοφόροι (Σηματοφορείς) Ταυτόχρονος Προγραμματισμός 1

Υλοποίηση Σηματοφόρων

Σηματοφόροι (Σηματοφορείς) Ταυτόχρονος Προγραμματισμός 1

Συστηματικός έλεγχος ορθότητας ταυτόχρονων προγραμμάτων μέσω γράφου καταστάσεων

Συστηματικός έλεγχος ορθότητας ταυτόχρονων προγραμμάτων μέσω γράφου καταστάσεων

Dr. Garmpis Aristogiannis - EPDO TEI Messolonghi

Αμοιβαίος αποκλεισμός

Ελεγκτές/Παρακολουθητές (Monitors) Ταυτόχρονος Προγραμματισμός 1

Διεργασίες (Processes)

Προσπέλαση σύνθετων δομών δεδομένων χωρίς καθολικό κλείδωμα

Προσπέλαση σύνθετων δομών δεδομένων χωρίς καθολικό κλείδωμα

Συγχρονισμός Μέρος Α : Κρίσιμο τμήμα και κλειδώματα

Αμοιβαίος αποκλεισμός με ασύγχρονη επικοινωνία (ανταλλαγή μηνυμάτων) Ταυτόχρονος Προγραμματισμός 1

Μάθημα 4 ο. Κρίσιμα Τμήματα και Αμοιβαίος Αποκλεισμός

Προβλήματα Συγχρονισμού (με ελεγκτή) Ταυτόχρονος Προγραμματισμός 1

Διεργασίες (μοντέλο μνήμης & εκτέλεσης) Προγραμματισμός II 1

Διεργασίες (μοντέλο μνήμης & εκτέλεσης) Προγραμματισμός II 1

Διάλεξη 9: Αλγόριθμοι Αμοιβαίου Αποκλεισμού με τη χρήση μεταβλητών Ανάγνωσης/Εγγραφής. ΕΠΛ 432: Κατανεμημένοι Αλγόριθμοι

Διάλεξη 8: Πρόβλημα Αμοιβαίου Αποκλεισμού. ΕΠΛ 432: Κατανεμημένοι Αλγόριθμοι

Συγχρονισμός & σηματοφόροι. Προγραμματισμός II 1

Ορθότητα λειτουργίας τμημάτων λογισμικού & δομών δεδομένων υπό ταυτόχρονη εκτέλεση

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΥΠΟΛΟΓΙΣΤΩΝ & ΥΠΟΛΟΓΙΣΤΙΚΗ ΦΥΣΙΚΗ

Διάλεξη 10: Αλγόριθμοι Αμοιβαίου Αποκλεισμού σε περιβάλλον ανταλλαγής μηνυμάτων. ΕΠΛ 432: Κατανεμημένοι Αλγόριθμοι

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

2.4 Κλασσικά Προβλήματα IPC

Λιβανός Γιώργος Εξάμηνο 2017Β

Λειτουργικά Συστήματα (ΗΥ222)

ΠΑΝΕΠΙΣΤΗΜΙΟ ΚΥΠΡΟΥ ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ

Δομές ελέγχου ροής προγράμματος

Εισαγωγικά & Βασικές Έννοιες

Νήµαταστην Java. Συγχρονισµός νηµάτων Επικοινωνία νηµάτων Εκτελέσιµα αντικείµενα Νήµατα δαίµονες Οµάδες νηµάτων. Κατανεµηµένα Συστήµατα 11-1

Τι είναι ένα λειτουργικό σύστημα (ΛΣ); Μια άλλη απεικόνιση. Το Λειτουργικό Σύστημα ως μέρος του υπολογιστή

Λειτουργικά Συστήματα (διαχείριση επεξεργαστή, μνήμης και Ε/Ε)

Προγραμματισμός Ι (HY120)

Εντοπισμός τερματισμού. Κατανεμημένα Συστήματα 1

Ορθότητα λειτουργίας τμημάτων λογισμικού & δομών δεδομένων υπό ταυτόχρονη εκτέλεση

Αδιέξοδα Ανάθεση Πόρων (Deadlocks Resource Allocation)

Θοδωρής Ανδρόνικος Τμήμα Πληροφορικής, Ιόνιο Πανεπιστήμιο

Όταν το πρόγραμμα φτάσει σε αυτή την εντολή και ο καταχωρητής PINA έχει την τιμή

Εισαγωγή στον Προγραμματισμό

Προβλήματα, αλγόριθμοι, ψευδοκώδικας

ΚΕΦΑΛΑΙΟ 9. Ταυτόχρονος προγραμματισμός και νήματα. 9.1 Εισαγωγή

Προγραμματισμός Ι (HY120)

Συνέπεια μνήμης σε πολυπύρηνα/πολυεπεξεργαστικά συστήματα

Πανεπιστήμιο Θεσσαλίας Τμήμα Ηλεκτρολόγων Μηχανικών & Μηχανικών Υπολογιστών Τμήμα Πληροφορικής

Αδιέξοδα Ανάθεση Πόρων (Deadlocks Resource Allocation)

Αδιέξοδα (Deadlocks)

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

Ορισµός Νήµα (thread) είναι µια ακολουθιακή ροή ελέγχου (δηλ. κάτι που έχει αρχή, ακολουθία εντολών και τέλος) σ ένα

Ασύγχρονο Σύστηµα ιαµοιραζόµενης Μνήµης Το σύστηµα περιέχει n διεργασίες p 0,, p n-1 και m καταχωρητές R 0,, R m-1. Κάθε διεργασία µοντελοποιείται ως

Mπαρμπούτι. Ενδεικτικές Απαντήσεις Φύλλου Εργασίας. Τυχαιότητα

Προσπέλαση κοινών πόρων Πρωτόκολλα ελέγχου αμοιβαίου αποκλεισμού

Εργαστήριο 14. Συγχρονισμός Νημάτων (χρήση pthread_mutex_t, pthread_cond_t)

Υ- 07 Παράλληλα Συστήματα Συνέπεια και συνοχή μνήμης

Εισαγωγικά & Βασικές Έννοιες

Ιδιοκτησία Αντικειµένου

Εθνικό Μετσόβιο Πολυτεχνείο Σχολή Ηλεκτρολόγων Μηχ. και Μηχανικών Υπολογιστών Εργαστήριο Υπολογιστικών Συστημάτων. Συγχρονισμός

Το μάθημα. Λειτουργικά Συστήματα Πραγματικού Χρόνου Βασικές Έννοιες 6. Ενσωματωμένα Συστήματα (embedded systems) Παραδείγματα

Εθνικό Μετσόβιο Πολυτεχνείο Σχολή Ηλεκτρολόγων Μηχ. και Μηχανικών Υπολογιστών Εργαστήριο Υπολογιστικών Συστημάτων. Συγχρονισμός

for for for for( . */

Δημιουργία & Τερματισμός Διεργασιών. Προγραμματισμός II 1

ΔΙΕΡΓΑΣΙΕΣ. Λειτουργικά Συστήματα Ι. Διδάσκων: Καθ. Κ. Λαμπρινουδάκης ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Ι

Ποια ιδιότητα αϖό τις δύο τελευταίες είναι ϖιο ισχυρή;

Κεφάλαιο 3. Διδακτικοί Στόχοι

Χώροι Πλειάδων (Tuple Spaces) Ταυτόχρονος Προγραμματισμός 1

Μεταγλωττιστές Βελτιστοποίηση

ΠΛΗΡΟΦΟΡΙΚΗ Ι JAVA Τμήμα θεωρίας με Α.Μ. σε 3, 7, 8 & 9 6/12/07

Βασικές έννοιες. Κατανεμημένα Συστήματα 1

Τμήμα Οικιακής Οικονομίας και Οικολογίας. Οργάνωση Υπολογιστών

ιεργασίες και νήµατα Προγραµµατισµός ΙΙΙ 1 lalis@inf.uth.gr

Τυχαίοι αριθμοί ρίξε μια «ζαριά»

Κεφάλαιο 4 Σημασιολογία μιας Απλής Προστακτικής Γλώσσας

ΕΘΝΙΚΟ ΜΕΤΣΟΒΙΟ ΠΟΛΥΤΕΧΝΕΙΟ ΣΧΟΛΗ ΗΛΕΚΤΡΟΛΟΓΩΝ ΜΗΧΑΝΙΚΩΝ ΚΑΙ ΜΗΧΑΝΙΚΩΝ ΥΠΟΛΟΓΙΣΤΩΝ ΤΟΜΕΑΣ ΤΕΧΝΟΛΟΓΙΑΣ ΠΛΗΡΟΦΟΡΙΚΗΣ ΚΑΙ ΥΠΟΛΟΓΙΣΤΩΝ

Λειτουργικά Συστήματα. Τ.Ε.Ι. Ιονίων Νήσων Σχολή Διοίκησης και Οικονομίας - Λευκάδα

Λειτουργικά Συστήματα Πραγματικού Χρόνου

ΠΛΗΡΟΦΟΡΙΚΗ Ι Ενότητα 3: Συναρτήσεις

Λειτουργικά συστήματα πραγματικού χρόνου

Προγραμματισμός Ι (ΗΥ120)

ΕΝΟΤΗΤΑ 4 Λήψη Αποφάσεων και Συναρτήσεις Ελέγχου

Διαδικασιακός Προγραμματισμός

Μεταγλώττιση και σύνδεση πολλαπλών αρχείων κώδικα. Προγραμματισμός II 1

Είδη εντολών. Απλές εντολές. Εντολές ελέγχου. Εκτελούν κάποια ενέργεια. Ορίζουν τον τρόπο με τον οποίο εκτελούνται άλλες εντολές

Δημιουργία & Τερματισμός Διεργασιών. Προγραμματισμός II 1

ΤΕΙ ΙΟΝΙΩΝ ΝΗΣΩΝ ΣΧΟΛΗ ΔΙΟΙΚΗΣΗΣ ΚΑΙ ΟΙΚΟΝΟΜΙΑΣ ΤΜΗΜΑ ΔΙΟΙΚΗΣΗΣ ΕΠΙΧΕΙΡΗΣΕΩΝ - ΕΙΣ

Χώροι Πλειάδων (Tuple Spaces) Ταυτόχρονος Προγραμματισμός 1

Εικονική Μνήμη (Virtual Memory) Προγραμματισμός II 1

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

Ανάπτυξη και Σχεδίαση Λογισμικού

Εικονική Μνήμη (Virtual Memory) Προγραμματισμός II 1

Μετρικές & Επιδόσεις. Κεφάλαιο V

Transcript:

Αμοιβαίος αποκλεισμός με κοινή μνήμη 1 lalis@inf.uth.gr

Το πρόβλημα Έστω ότι δύο η περισσότερα νήματα επιθυμούν να προσπελάσουν έναν κοινό πόρο, που όμως δεν μπορεί να χρησιμοποιηθεί ταυτόχρονα Η χρήση του πόρου πρέπει να γίνει με κατάλληλο συντονισμό ανάμεσα στα νήματα Η πλέον κλασική περίπτωση: ταυτόχρονη πρόσβαση νημάτων σε κοινές μεταβλητές (όπου μπορεί να προκύψουν ανεπιθύμητες συνθήκες ανταγωνισμού) 2 lalis@inf.uth.gr

3 lalis@inf.uth.gr

Παράδειγμα: χρήση κοινής μεταβλητής int i=0; P1: i=i+1 P2: i=i+1 tmp1=i i=tmp1+1 tmp2=i i=tmp2+1 Οι εντολές του ενός νήματος πιθανώς να μην εκτελεστούν ατομικά, χωρίς να μεσολαβήσει ανταγωνιστική εντολή του άλλου νήματος Μπορεί να προκύψει «ασυνέπεια» ως προς την τιμή που θα λάβει η κοινή μεταβλητή i 4 lalis@inf.uth.gr

Προσέγγιση Α Έχουμε συνειδητοποιήσει το πρόβλημα Γράφουμε κώδικα που επιτυγχάνει το επιθυμητό αποτέλεσμα ανεξάρτητα από την μη ατομικότητα των εντολών και τις εναλλαγές που ίσως γίνουν κατά την διάρκεια της εκτέλεσης του κώδικα Όμως Ο προγραμματιστής πρέπει να σκέφτεται / λύνει παρόμοια προβλήματα, κάθε φορά από την αρχή Υπάρχουν προβλήματα συγχρονισμού ανάμεσα σε νήματα που δεν μπορούν να λυθούν με απλό τρόπο 5 lalis@inf.uth.gr

Προσέγγιση Β Προσπαθούμε να μοντελοποιήσουμε το πρόβλημα και την λύση του με γενικό τρόπο, έτσι ώστε να μπορεί να χρησιμοποιηθεί σε πολλές περιπτώσεις Θετικά Η λύση είναι επαναχρησιμοποιήσιμη Διευκολύνεται η κατασκευή ορθών προγραμμάτων Αρνητικά Η γενική λύση ίσως επιφέρει επιπλέον κόστος εκτέλεσης (overhead) 6 lalis@inf.uth.gr

Κρίσιμο τμήμα Έστω ότι ο κώδικας ενός νήματος περιέχει μια ακολουθία εντολών εντολές που πρέπει εκτελεστούν χωρίς την παρεμβολή ανταγωνιστικού κώδικα Ένα τέτοιο τμήμα κώδικα ονομάζεται κρίσιμο τμήμα (critical section) Κάθε νήμα μπορεί να έχει πολλά κρίσιμα τμήματα, σε σχέση με ένα ή περισσότερα άλλα νήματα 7 lalis@inf.uth.gr

P Q R p1; p2; p3; p4; p5; p6; p7; p8; p9; q1; q2; q3; q4; q5; q6; q7; q8; q9; r1; r2; r3; r4; r5; r6; r7; r8; r9; 8 lalis@inf.uth.gr

P Q R p1; p2; p3; p4; p5; p6; p7; p8; p9; q1; q2; q3; q4; q5; q6; q7; q8; q9; r1; r2; r3; r4; r5; r6; r7; r8; r9; 9 lalis@inf.uth.gr

P Q R p1; p2; p3; p4; p5; p6; p7; p8; p9; q1; q2; q3; q4; q5; q6; q7; q8; q9; r1; r2; r3; r4; r5; r6; r7; r8; r9; 10 lalis@inf.uth.gr

Σημείωση Ο μεταγλωττιστής, το περιβάλλον ταυτόχρονης εκτέλεσης και το λειτουργικό δεν γνωρίζουν την σημασία των δεδομένων και του κώδικα του προγράμματος σε επίπεδο εφαρμογής Ο ίδιος ο προγραμματιστής είναι υπεύθυνος να εντοπίσει στον κώδικα του τα τμήματα που είναι όντως κρίσιμα ανάλογα με την επιθυμητή λειτουργικότητα του προγράμματος 11 lalis@inf.uth.gr

int i=0; P1: int k; for (k=0; k<n; k++) { i=i+1; } P2: int k; for (k=0; k<n; k++) { i=i+1; } Επιθυμητή λειτουργικότητα: στο τέλος της εκτέλεσης η i πρέπει να έχει την τιμή 2Ν οι εντολές i=i+1 αποτελούν κρίσιμο τμήμα 12 lalis@inf.uth.gr

int i=0; P1: while (i<2*n) { i=i+1; } P2: while (i<2*n) { i=i+1; } Επιθυμητή λειτουργικότητα: στο τέλος της εκτέλεσης η i πρέπει να έχει την τιμή >=2Ν οι εντολές i=i+1 δεν αποτελούν κρίσιμο τμήμα 13 lalis@inf.uth.gr

Ιδιότητες της λύσης του ΚΤ 1. Αμοιβαίος αποκλεισμός (mutual exclusion): αν ένα νήμα βρίσκεται μέσα στο ΚΤ του, τότε κανένα άλλο νήμα δεν θα εισέλθει στο δικό του ΚΤ 2. Πρόοδος (progress): αν ένα νήμα επιθυμεί να εισέλθει στο ΚΤ του, τελικά θα το καταφέρει Απουσία αδιεξόδου (no deadlock): δεν υπάρχει περίπτωση τα νήματα να εμποδίζουν το ένα το άλλο από το να εισέλθει στο ΚΤ έτσι ώστε κανένα νήμα να μην καταφέρει ποτέ να εισέλθει στο ΚΤ Απουσία λιμοκτονίας (no starvation): δεν υπάρχει περίπτωση ένα συγκεκριμένο νήμα να μην καταφέρει ποτέ να μπει στο ΚΤ ενώ άλλα νήματα το καταφέρνουν ή δεν ενδιαφέρονται να μπουν στο ΚΤ 14 lalis@inf.uth.gr

P1 P2 P3 P1 P2 P3 1) 2) CS CS P1 P2 P3 P2 P3 3) CS 4) P1 CS P1 15 lalis@inf.uth.gr

Κώδικας συγχρονισμού Οι λύσεις που θα εξετάσουμε αποτελούνται από δύο τμήματα κώδικα ανά κρίσιμο τμήμα Κώδικας εισόδου: εντολές πριν το ΚΤ, με κύριο σκοπό τον αμοιβαίο αποκλεισμό Κώδικας εξόδου: εντολές μετά το ΚΤ, με κύριο σκοπό την πρόοδο των νημάτων που τυχόν περιμένουν (στον κώδικα εισόδου) Ο κώδικας εισόδου και εξόδου σχεδιάζονται σε στενό συνδυασμό μεταξύ τους Οι λύσεις είναι συχνά συμμετρικές: όλα τα νήματα εκτελούν (σχεδόν) τον ίδιο κώδικα 16 lalis@inf.uth.gr

Υποθέσεις εργασίας Κάθε νήμα λαμβάνει τακτικά τον επεξεργαστή Όμως, δεν γίνεται καμία υπόθεση για το πόσες φορές / σε ποια σημεία θα γίνει εναλλαγή κατά την εκτέλεση κάθε νήματος, ούτε για το πιο νήμα θα επιλεγεί σε κάθε εναλλαγή Δεν γίνεται καμία υπόθεση για το αν και πόσες φορές ένα νήμα θα επιχειρήσει να εισέλθει στο ΚΤ Ένα νήμα δεν μπορεί να τερματιστεί κατά την εκτέλεση του κώδικα συγχρονισμού ή του ΚΤ 17 lalis@inf.uth.gr

P0 δεν γνωρίζουμε αν και πόσες φορές ένα νήμα θα φτάσει σε αυτό το σημείο του κώδικα P1 while () { if () { entrycode0 while () { if () { entrycode1 ΚΤ του P0 CS0 μας ενδιαφέρει αυτός ο κώδικας CS1 ΚΤ του P1 } } exitcode0 } } exitcode1 18 lalis@inf.uth.gr

Σημείωση Ο κώδικας εισόδου και ο κώδικας εξόδου αποτελείται (και αυτός) από συμβατικές εντολές Τα πρόβλημα της μη ατομικότητας των εντολών εξακολουθεί να υφίσταται και για τον κώδικα εισόδου/εξόδου όπως και για το κρίσιμο τμήμα Ο κώδικας εισόδου και εξόδου γράφεται με πλήρη επίγνωση της μη ατομικότητας, και έτσι ώστε να ικανοποιούνται οι ιδιότητες του ΚΤ Αυτό δεν είναι τόσο απλό 19 lalis@inf.uth.gr

Αλγόριθμος Α (2 νήματα) int turn=0; P0: while (turn!=0) {} P1: while (turn!=1) {} CS0 turn=1; CS1 turn=0; Ένα νήμα εισέρχεται στο ΚΤ όταν είναι η σειρά του Όταν βγει από το ΚΤ, δίνει σειρά στο άλλο νήμα 20 lalis@inf.uth.gr

Αλγόριθμος Α (2 νήματα) int turn=0; P0: while (turn!=0) {} P1: while (turn!=1) {} CS0 turn=1; CS1 turn=0; Ένα νήμα εισέρχεται στο ΚΤ όταν είναι η σειρά του Όταν βγει από το ΚΤ, δίνει σειρά στο άλλο νήμα εγγυάται αμοιβαίο αποκλεισμό γιατί; δεν εγγυάται πρόοδο γιατί; 21 lalis@inf.uth.gr

main: turn=0 P0: (turn!=0) /* false, exit while */ P0: CS0 P1: P1: P0: CS0 P0: turn=1; P1: P1: P0: (turn!=0) /* true, repeat while */ P0: (turn!=0) /* true, repeat while */ P1: P1: 22 lalis@inf.uth.gr

Αλγόριθμος Β (2 νήματα) int turn; P0: turn=0; while (turn!=0) {} CS0 turn=1; P1: turn=1; while (turn!=1) {} CS1 turn=0; Όπως προηγουμένως, αλλά τώρα κάθε νήμα «δηλώνει» (έμμεσα) την πρόθεση του να εισέλθει στο ΚΤ, δίνοντας την σειρά στον εαυτό του 23 lalis@inf.uth.gr

Αλγόριθμος Β (2 νήματα) int turn; P0: turn=0; while (turn!=0) {} CS0 turn=1; P1: turn=1; while (turn!=1) {} CS1 turn=0; Όπως προηγουμένως, αλλά τώρα κάθε νήμα «δηλώνει» (έμμεσα) την πρόθεση του να εισέλθει στο ΚΤ, δίνοντας την σειρά στον εαυτό του δεν εγγυάται αμοιβαίο αποκλεισμό γιατί; 24 lalis@inf.uth.gr

main: turn=0 P0: turn=0 P0: (turn!=0) /* false, exit while */ P0: CS0 P1: turn=1 P1: (turn!=1) /* false, exit while */ P1: CS1 25 lalis@inf.uth.gr

Αλγόριθμος Γ (2 νήματα) bool entercs[2]={false,false}; P0: entercs[0]=true; while (entercs[1]) {} CS0 entercs[0]=false; P1: entercs[1]=true; while (entercs[0]) {} CS1 entercs[1]=false; Επανάληψη της προηγούμενης ιδέας, αλλά με δύο ξεχωριστές μεταβλητές πρόθεσης εισόδου 26 lalis@inf.uth.gr

Αλγόριθμος Γ (2 νήματα) bool entercs[2]={false,false}; P0: entercs[0]=true; while (entercs[1]) {} CS0 entercs[0]=false; P1: entercs[1]=true; while (entercs[0]) {} CS1 entercs[1]=false; Επανάληψη της προηγούμενης ιδέας, αλλά με δύο ξεχωριστές μεταβλητές πρόθεσης εισόδου εγγυάται αμοιβαίο αποκλεισμό γιατί; δεν εγγυάται πρόοδο γιατί; 27 lalis@inf.uth.gr

main: main: entercs[0]=false entercs[1]=false P0: entercs[0]=true P1: entercs[1]=true P0: (entercs[1]) /* true, repeat while */ P1: (entercs[0]) /* true, repeat while */ P0: (entercs[1]) /* true, repeat while */ P1: (entercs[0]) /* true, repeat while */ 28 lalis@inf.uth.gr

Αλγόριθμος Δ (2 νήματα) bool entercs[2]={false,false}; P0: entercs[0]=true; while (entercs[1]) { entercs[0]=false; entercs[0]=true; } CS0 entercs[0]=false; P1: entercs[1]=true; while (entercs[0]) { entercs[1]=false; entercs[1]=true; } CS1 entercs[1]=false; Κατά την αναμονή, το ένα νήμα δίνει στο άλλο (προς στιγμή) την ευκαιρία να εισέλθει στο ΚΤ 29 lalis@inf.uth.gr

Αλγόριθμος Δ (2 νήματα) bool entercs[2]={false,false}; P0: entercs[0]=true; while (entercs[1]) { entercs[0]=false; entercs[0]=true; } CS0 entercs[0]=false; P1: entercs[1]=true; while (entercs[0]) { entercs[1]=false; entercs[1]=true; } CS1 entercs[1]=false; Κατά την αναμονή, το ένα νήμα δίνει στο άλλο (προς στιγμή) την ευκαιρία να εισέλθει στο ΚΤ πάλι δεν υπάρχει απόλυτα εγγυημένη πρόοδος 30 lalis@inf.uth.gr

main: main: entercs[0]=false entercs[1]=false P0: entercs[0]=true P1: entercs[1]=true P0: (entercs[1]) /* true, enter while */ P1: (entercs[0]) /* true, enter while */ P0: entercs[0]=false P0: entercs[0]=true P1: entercs[1]=false P1: entercs[1]=true P0: (entercs[1]) /* true, enter while */ P1: (entercs[0]) /* true, enter while */ 31 lalis@inf.uth.gr

Παρατηρήσεις H λύση είναι τυπικά λανθασμένη Παρόλα αυτά, μια τέτοια «ατυχής» εναλλαγή θα μπορούσε να θεωρηθεί εντελώς απίθανη στην πράξη η λύση θα μπορούσε να χαρακτηριστεί ως ικανοποιητική (τουλάχιστον για μη-κρίσιμα συστήματα) Όμως, αυτή η υπόθεση απαιτεί προσοχή Π.χ. αν γίνεται συστηματική εναλλαγή κάθε εντολή ή κάθε δεύτερη εντολή, υπάρχει σίγουρη λιμοκτονία Μπορεί να μειωθεί (από τον προγραμματιστή) η πιθανότητα μιας «ατυχούς» εκτέλεσης; 32 lalis@inf.uth.gr

Αλγόριθμος Δ2 (2 νήματα) bool entercs[2]={false,false}; P0: entercs[0]=true; while (entercs[1]) { entercs[0]=false; sleep(random); entercs[0]=true; } CS0 entercs[0]=false; P1: entercs[1]=true; while (entercs[0]) { entercs[1]=false; sleep(random); entercs[1]=true; } CS1 entercs[1]=false; Υπάρχει εγγύηση προόδου; 33 lalis@inf.uth.gr

Αλγόριθμος Δ3 (2 νήματα) bool entercs[2]={false,false}; P0: entercs[0]=true; while (entercs[1]) { entercs[0]=false; while (entercs[1]) {} entercs[0]=true; } CS0 entercs[0]=false; P1: entercs[1]=true; while (entercs[0]) { } CS1 entercs[1]=false; Υπάρχει εγγύηση προόδου; 34 lalis@inf.uth.gr

Αλγόριθμος Dekker int turn=0; bool entercs[2]={false,false}; P0: entercs[0]=true; while (entercs[1]) { if (turn==1) { entercs[0]=false; while (turn==1) {} entercs[0]=true; } } CS0 turn=1; entercs[0]=false; P1: entercs[1]=true; while (entercs[0]) { if (turn==0) { entercs[1]=false; while (turn==0) {} entercs[1]=true; } } CS1 turn=0; entercs[1]=false; 35 lalis@inf.uth.gr

Παρατήρηση Ο αλγόριθμος συνδυάζει τους αλγορίθμους Α και Δ, με την μεταβλητή turn να παίζει τον ρόλο της προτεραιότητας σε περίπτωση ανταγωνισμού Αν και τα δύο νήματα επιχειρήσουν να εισέλθουν στο ΚΤ ταυτόχρονα, όπως πριν, και τα δύο θα μπουν στον βρόγχο αναμονής, αλλά τώρα μόνο ένα θα μείνει μέσα στον βρόγχο (αυτό που δεν έχει σειρά) Από τη στιγμή που ένα νήμα μείνει στον βρόγχο είναι σίγουρο ότι τελικά θα εισέλθει στο ΚΤ, με το που το άλλο νήμα βγει από το ΚΤ και του δώσει την σειρά Αφού υπάρχει ρητή σειρά εισόδου που αλλάζει όταν ένα νήμα βγει από το ΚΤ, δεν μπορεί να γίνονται προσπεράσματα (για πάντα) 36 lalis@inf.uth.gr

Σενάριο προσπεράσματος Ο αλγόριθμος δεν αποκλείει πλήρως το προσπέρασμα Η είσοδος στο ΚΤ υπό συνθήκες ανταγωνισμού δεν είναι εγγυημένα εναλλάξ Π.χ., παρότι είναι σειρά του P0 να μπει στο ΚΤ, αν αυτό δεν λάβει τον επεξεργαστή, μπορεί να προσπεραστεί από το P1, το οποίο να μπει για πολλοστή συνεχόμενη φορά στο ΚΤ Όμως, από την στιγμή που το P0 λάβει τον έλεγχο, και επαναφέρει το entercs[0]=true, δεν μπορεί πλέον να υπάρξει τέτοιο προσπέρασμα Έχουμε υποθέσει ότι τα νήματα λαμβάνουν τακτικά τον επεξεργαστή => το P0 σίγουρα θα λάβει κάποια στιγμή τον έλεγχο, και τελικά θα μπει στο ΚΤ 37 lalis@inf.uth.gr

Άτυπη απόδειξη ορθότητας Λόγω συμμετρίας, αν αποδείξουμε τις παραπάνω ιδιότητες για P0, τις έχουμε αποδείξει και για P1 1. Αμοιβαίος αποκλεισμός: Αν «P0 είναι στο ΚΤ» τότε «P1 δεν είναι στο ΚΤ» 2. Πρόοδος: Αν «P0 επιθυμεί να μπει στο ΚΤ» τότε τελικά «P0 είναι στο ΚΤ» 38 lalis@inf.uth.gr

Αμοιβαίος αποκλεισμός Α) P1 επιχειρεί να μπει στο ΚΤ ενώ P0 είναι ήδη στο KT entercs[0] είναι true P1 θα περιμένει στον εξωτερικό ή/και εσωτερικό βρόγχο αναμονής, ανάλογα με την τιμή της turn Β) P0 και P1 επιχειρούν να μπουν στο ΚΤ ταυτόχρονα entercs[0] και entercs[1] γίνονται true, προτού γίνει έλεγχος της συνθήκης αναμονής από P0 ή P1 P0 και P1 θα μπουν στον εξωτερικό βρόγχο αναμονής έστω ότι turn είναι 0 P1 θα θέσει entercs[1] σε false, και θα περιμένει στον εσωτερικό βρόγχο η τιμή της turn δεν αλλάζει (μένει 0) όσο το P0 είναι στο ΚΤ P1 θα περιμένει στον εσωτερικό βρόγχο 39 lalis@inf.uth.gr

Πρόοδος Α) Μόνο το P0 θέλει να μπει στο ΚΤ, ενώ P1 όχι entercs[1] είναι false, P0 θα εισέλθει άμεσα στο ΚΤ Β1) P0 και P1 θέλουν να μπουν στο ΚΤ, και turn είναι 0 βλέπε σενάριο ΑΑ.Β P0 θα εξέλθει από τον εξωτερικό βρόγχο, και θα μπει στο ΚΤ Β2) P0 και P1 θέλουν να μπουν στο ΚΤ, και turn είναι 1 P0 θα περιμένει, στον εξωτερικό ή/και εσωτερικό βρόγχο P1 θα βγει από ΚΤ, entercs[1] θα γίνει false, turn θα γίνει 0 αν P0 είναι στον εσωτερικό βρόγχο θα βγει από αυτόν αν P1 δεν επιχειρήσει να ξαναμπεί στο ΚΤ, η entercs[1] θα μείνει false, P0 θα βγει (και) από τον εξωτερικό βρόγχο και θα εισέλθει στο ΚΤ αν P1 επιχειρήσει να μπει ξανά στο ΚΤ, βλέπε Β1 40 lalis@inf.uth.gr

Βελτιστοποίηση Συνδυασμός ελέγχου των 2 συνθηκών «μήπως επιχειρεί και το άλλο νήμα να μπει στο ΚΤ αυτή τη στιγμή;» «μήπως είναι η σειρά μου να μπω στο ΚΤ;» Αρκεί ένας βρόγχος αναμονής, μέσω του οποίου πραγματοποιούνται και οι δύο παραπάνω έλεγχοι Αλγόριθμος του Peterson Συνδυασμός των αλγορίθμων Β και Γ Η διαφορά σε σχέση με τον Β είναι ότι η σειρά προτεραιότητας, που αλλάζει πριν τον έλεγχο της συνθήκης αναμονής, δίνεται στο άλλο νήμα 41 lalis@inf.uth.gr

Αλγόριθμος Peterson int turn; int entercs[2]={false,false}; P0: entercs[0]=true; turn=1; while (entercs[1]) { if (turn==0) { break; } } CS0 entercs[0]=false; P1: entercs[1]=true; turn=0; while (entercs[0]) { if (turn==1) { break; } } CS1 entercs[1]=false; 42 lalis@inf.uth.gr

Αλγόριθμος Peterson int turn; int entercs[2]={false,false}; P0: entercs[0]=true; turn=1; while ((entercs[1]) && (turn!=0)) {} CS0 entercs[0]=false; P1: entercs[1]=true; turn=0; while ((entercs[0]) && (turn!=1)) {} CS1 entercs[1]=false; 43 lalis@inf.uth.gr

Παρατήρηση Παρότι, όπως και στον αλγόριθμο Β, και τα δύο νήματα αλλάζουν-ελέγχουν την turn ταυτόχρονα, αντίθετα με τον αλγόριθμο Β, σε αυτή την περίπτωση είναι εγγυημένος ο αμοιβαίος αποκλεισμός Γιατί: όταν ένα νήμα αλλάζει την turn δίνει προτεραιότητα στο άλλο νήμα (όχι στον εαυτό του) Ο αλγόριθμος δεν θα ήταν σωστός αν κάθε νήμα που επιχειρεί να εισέλθει στο ΚΤ έδινε προτεραιότητα στον εαυτό του η αλλαγή της turn (υπέρ του άλλου νήματος) γινόταν μετά την έξοδο από το ΚΤ 44 lalis@inf.uth.gr

Αλγόριθμος Bakery (Lamport) Σε περίπτωση ανταγωνισμού, η προτεραιότητα καθορίζεται μέσω ενός εισιτηρίου (ticket) t[i] Αν το Pi δεν έχει πρόθεση να μπει στο ΚΤ, t[i]==0 Διαφορετικά, το Pi λαμβάνει το εισιτήριο του t[i] αυξάνοντας κατά 1 το εισιτήριο t[(i+1)%2] του ανταγωνιστικού νήματος P(i+1)%2 Το νήμα με τον μικρότερο αριθμό εισέρχεται στο ΚΤ Δεν υπάρχει περίπτωση ένα νήμα να εισέλθει δύο συνεχόμενες φορές στο ΚΤ ενώ περιμένει το άλλο Στην δεύτερη απόπειρα θα λάβει σίγουρα μεγαλύτερο αριθμό εισιτηρίου από το νήμα που ήδη περιμένει να μπει στο ΚΤ 45 lalis@inf.uth.gr

Σύγκριση εισιτηρίων int priority(self,i) { if (t[i]==0) // Pi not competing => I have priority return(1); else if (t[self]<t[i]) // I have priority return(1); else if (t[self]>t[j]) // Pi has priority return(0); else // same ticket => tie-break based on ids return(self<=i); } Μηδενική τιμή συνεπάγεται μη ύπαρξη ανταγωνισμού (το άλλο νήμα δεν ενδιαφέρεται να εισέλθει στο ΚΤ) Αν, λόγω ταυτόχρονης εκτέλεσης, δύο νήματα λάβουν τον ίδιο αριθμό εισιτηρίου, προτεραιότητα δίνεται στο νήμα με το μικρότερο αναγνωριστικό 46 lalis@inf.uth.gr

Αλγόριθμος Bakery / FIFO (Lamport) int t[2]={0,0}; int taking[2]={false,false}; P0: taking[0]=true; t[0] = t[1] + 1; taking[0]=false; while (taking[1]) {} while (!priority(0,1)){} CS0 t[0]=0; P1: taking[1]=true; t[1] = t[0] + 1; taking[1]=false; while (taking[0]) {} while (!priority(1,0)){} CS1 t[1]=0; 47 lalis@inf.uth.gr

Η μεταβλητή taking Αν taking[i]==true, το εισιτήριο του Pi βρίσκεται υπό κατασκευή, και δεν μπορεί να χρησιμοποιηθεί για τον έλεγχο προτεραιότητας Αν taking[i]==false, το Pi είτε έχει εισιτήριο 0, είτε έχει λάβει εισιτήριο >0, και σε κάθε περίπτωση το εισιτήριο του Pi μπορεί να χρησιμοποιηθεί με ασφάλεια για τον έλεγχο προτεραιότητας Αν, αφού ένα νήμα ελέγξει ότι taking[i]==false, αλλά προτού ελέγξει την προτεραιότητα, το Pi λάβει εισιτήριο, αυτό θα είναι εγγυημένα μεγαλύτερο από το εισιτήριο του άλλου νήματος 48 lalis@inf.uth.gr

Αλγόριθμος Bakery / FIFO (Lamport) int t[2]={0,0}; int taking[2]={false,false}; P0: taking[0]=true; tmp0 = t[1]; t[0] = tmp0 + 1; taking[0]=false; while (taking[1]) {} while (!priority(0,1)){} CS0 t[0]=0; P1: taking[1]=true; tmp1 = t[0]; t[1] = tmp1 + 1; taking[1]=false; while (taking[0]) {} while (!priority(1,0)){} CS1 t[1]=0; 49 lalis@inf.uth.gr

Χωρίς την «προστασία» της taking main: main: t[0]=0; t[1]=0; P0: tmp0=t[1] /* tmp0 is 0 */ P1: tmp1=t[0] /* tmp1 is 0 */ P1: t[1]=tmp1+1 /* t[1] is 1 */ P1: (priority(1,0)) /* true, exit while */ P1: CS1 P0: t[0]=tmp0+1 /* t[0] is 1 */ P0: (priority(0,1)) /* true, exit while */ P0: CS0 50 lalis@inf.uth.gr

Αλγόριθμος Bakery για Ν νήματα int t[ν]={0,,0}; int taking[ν]={false,,false}; Pi: while (1) { taking[i]=true; t[i] = max(t[0],t[1],, t[n-1]) + 1; taking[i]=false; for (j=0; j<ν; j++) { while (taking[j]) {} while (!priority(i,j)) {} } CSi } t[i]=0; 51 lalis@inf.uth.gr

Παρατηρήσεις Οι προηγούμενες λύσεις βασίζονται αποκλειστικά σε συμβατικό κώδικα (είναι γενικότερα εφαρμόσιμες) Χωρίς να γίνεται καμία (περιοριστική) υπόθεση εργασίας για την εκτέλεση των νημάτων Χωρίς να υπάρχει κανένας έλεγχος της εναλλαγής Χωρίς να γίνεται χρήση ειδικών εντολών υλικού Όμως: Για κάθε ΚΤ χρειάζεται ξεχωριστό σετ μεταβλητών Υπάρχει ενεργή αναμονή Ο αριθμός των ανταγωνιστικών νημάτων ανά ΚΤ πρέπει να είναι γνωστός εκ των προτέρων 52 lalis@inf.uth.gr

Ειδικές εντολές σε επίπεδο υλικού Οι επεξεργαστές προσφέρουν ειδικές ατομικές εντολές που μπορεί να χρησιμοποιηθούν για τον συγχρονισμό ανάμεσα σε νήματα με κοινή μνήμη Π.χ. test-and-set ή compare-and-swap int TAS(int *v) { int oldv; int CAS(int* v, int curv, int newv) { int oldv; } ATOMIC oldv=*v; *v=1; END_ATOMIC return(oldv); } ATOMIC oldv = *v; if (oldv == curv) *v=newv; END_ATOMIC return(oldv); 53 lalis@inf.uth.gr

Κρίσιμο τμήμα με TAS και CAS int lock=0; Pi: while (TAS(&lock)){} CSi lock = 0; int lock=0; Pi: while (CAS(&lock,0,1)){} CSi lock = 0; Η λύση ισχύει για άγνωστο αριθμό νημάτων Δεν εγγυάται πρόοδο γιατί; 54 lalis@inf.uth.gr

Χωρίς ενεργή αναμονή 55 lalis@inf.uth.gr

Ενεργή αναμονή (busy waiting) Κατά την αναμονή στον κώδικα εισόδου ενός ΚΤ ξοδεύεται χρόνος του επεξεργαστή χωρίς νόημα Αυτό καθυστερεί την πρόοδο των υπολοίπων νημάτων συμπεριλαμβανομένου και του νήματος που βρίσκεται μέσα στο ΚΤ Όσο περισσότερα νήματα εκτελούν ενεργή αναμονή, τόσο πιο αργά προοδεύει το νήμα που βρίσκεται μέσα στο ΚΤ και τόσο πιο αργά θα βγει από το ΚΤ 56 lalis@inf.uth.gr

P0 P1 P0: CS0 P0: CS0 P0: CS0 P1: while () P1: while () P1: while () P0: CS0 P0: CS0 P0: CS0 P1: while () P1: while () P1: while () P0: CS0 P0: CS0 P0: CS0 P1: while () 57 lalis@inf.uth.gr

Εθελοντική (ρητή) εναλλαγή Όσο δεν ικανοποιείται η συνθήκη εισόδου, το νήμα μπορεί να παραχωρήσει (εθελοντικά) την CPU Έτσι ώστε να συνεχιστεί, άμεσα, η εκτέλεση κάποιου άλλου νήματος που είναι σε κατάσταση ετοιμότητας Ο χαμένος χρόνος της CPU μειώνεται σημαντικά χωρίς ρητή εναλλαγή while (<!cond>) {} CS establish <cond> με ρητή εναλλαγή while (<!cond>) {yield();} CS establish <cond> yield(); /* be nice */ 58 lalis@inf.uth.gr

P0 P1 P0: CS0 P0: CS0 P0: CS0 P1: while () yield() P0: CS0 P0: CS0 P0: CS0 P1: while () yield() P0: CS0 P0: CS0 P0: CS0 P1: while () yield() P0: CS0 P0: CS0 P0: CS0 P1: while () yield() P0: CS0 59 lalis@inf.uth.gr

Χωρίς ενεργή αναμονή Η ρητή παραχώρηση του επεξεργαστή δεν λύνει εντελώς το πρόβλημα της ενεργής αναμονής Απλά το κάνει λιγότερο επώδυνο Εξακολουθεί να χάνεται χρόνος του επεξεργαστή για τον έλεγχο της συνθήκης εισόδου και την εναλλαγή Το ιδανικό Τα νήματα να απενεργοποιούνται πλήρως, μέχρι να έρθει η σειρά τους να εισέλθουν στο ΚΤ 60 lalis@inf.uth.gr

Απαλοιφή ενεργής αναμονής Έστω ότι το σύστημα παρέχει τις λειτουργίες αναμονής και αφύπνισης WAIT & WAKEUP Η απαλοιφή της ενεργής αναμονής φαίνεται μάλλον εύκολη υπόθεση Αντί το νήμα να ελέγχει συνεχώς/ενεργά την συνθήκη, καλεί την WAIT και τίθεται σε αναμονή Αντίστοιχα, όταν ένα νήμα αλλάζει την συνθήκη, αφυπνίζει το νήμα που περιμένει μέσω της WAKEUP Όμως, λύσεις τέτοιου τύπου είναι ιδιαίτερα ευάλωτες σε συνθήκες ανταγωνισμού 61 lalis@inf.uth.gr

int locked=0; Pi: while (1) { if (TAS(&locked)) { WAIT(); } γιατί αυτή η λύση δεν είναι σωστή; CSi } locked=0; WAKEUP(); 62 lalis@inf.uth.gr

int locked=0; Pi: while (1) { while (TAS(&locked)) { WAIT(); } γιατί αυτή η λύση δεν είναι σωστή; CSi } locked=0; WAKEUP(); 63 lalis@inf.uth.gr

Υποστήριξη συγχρονισμού σε ψηλό επίπεδο Ο έλεγχος της εναλλαγής και η εγγύηση ατομικής εκτέλεσης κώδικα υπάρχει συνήθως ως δυνατότητα μόνο στο επίπεδο/περιβάλλον που υλοποιεί τους μηχανισμούς της ταυτόχρονης εκτέλεσης, π.χ., λειτουργικό, βιβλιοθήκη νημάτων, Με την σειρά τους, τα περιβάλλοντα εκτέλεσης παρέχουν στον προγραμματιστή άλλα «εργαλεία» συγχρονισμού: σηματοφόροι, ελεγκτές, 64 lalis@inf.uth.gr

Η ενεργή αναμονή μπορεί να είναι καλή ιδέα Σε συστήματα με πολλές CPU, η ενεργή αναμονή (μέσω spinlocks) είναι λιγότερο προβληματική Απλά χάνεται ο χρόνος της CPU που τρέχει το νήμα που πραγματοποιεί ενεργή αναμονή (χωρίς να υπάρχει το κόστος μιας εναλλαγής) Αν η παραμονή των νημάτων στο ΚΤ είναι σύντομη, η ενεργή αναμονή μπορεί να είναι πιο αποδοτική από μια κλήση συστήματος που με την σειρά της ίσως οδηγήσει σε απενεργοποίηση του νήματος και εναλλαγή 65 lalis@inf.uth.gr

P1 P2 L1 TAS lock,tmp cmp tmp,0 brneq L1 // CS store 0,lock CPU lock shared memory L1 TAS lock,tmp cmp tmp,0 brneq L1 // CS store 0,lock CPU P1 P2 lock unlock lock unlock lock unlock CS CS spin CS lock unlock lock unlock lock unlock spin CS CS CS Προγραμματισμός ΙΙΙ 66 lalis@inf.uth.gr