Σηματοφόροι (Σηματοφορείς) 1 lalis@inf.uth.gr
Αποφυγή ενεργής αναμονής if () { WAIT(); Μπορεί να γίνει εναλλαγή αφού το νήμα κάνει τον έλεγχο της συνθήκης αναμονής και την βρει αληθή, αλλά προτού αυτό προλάβει να μπλοκάρει Θέλουμε ατομικό έλεγχο της συνθήκης αναμονής και μπλοκάρισμα του νήματος αν αυτή ισχύει 2 lalis@inf.uth.gr
Σηματοφόροι (semaphores) Αφηρημένος τύπος δεδομένων με 3 λειτουργίες: init(sem s, int val) αρχικοποιεί τον σηματοφόρο στην τιμή val >=0 down(sem s) (ή wait ή P) επιχειρεί να μειώσει την τιμή του σηματοφόρου κατά 1 αν η τιμή του s είναι 0, το καλών νήμα μπλοκάρεται up(sem s) (ή signal ή V) αν υπάρχει μπλοκαρισμένο νήμα, αυτό ξεμπλοκάρεται διαφορετικά, αυξάνει την τιμή του σηματοφόρου κατά 1 Οι down/up λειτουργούν υπό ταυτόχρονη εκτέλεση η εσωτερική υλοποίηση δεν μας ενδιαφέρει (προς στιγμή) Γενικό εργαλείο συγχρονισμού 3 lalis@inf.uth.gr
up down init value thread queue sem s τρέχουσα τιμή σηματοφόρου ουρά νημάτων που έχουν μπλοκάρει στον σηματοφόρο 4 lalis@inf.uth.gr
Τύποι σηματοφόρων 1. Εύρος τιμών Γενικοί/μετρητές: >=0 Δυαδικοί: 0 ή 1 2. Προτεραιότητα/σειρά με την οποία ξεμπλοκάρονται (μέσω up) τα νήματα που έχουν μπλοκάρει στην down Random: η επιλογή γίνεται με τυχαία σειρά (θεωρητικά, υπάρχει περίπτωση λιμοκτονίας) Fair: η επιλογή γίνεται έτσι ώστε να μην υπάρχει περίπτωση λιμοκτονίας για κανένα νήμα FIFO: ξεμπλοκάρεται το νήμα που μπλόκαρε πριν από τα υπόλοιπα 5 lalis@inf.uth.gr
Κρίσιμο τμήμα με σηματοφόρους Αρκεί ένας δυαδικός σηματοφόρος Αρχικοποίηση: ο σηματοφόρος λαμβάνει την τιμή 1 Κώδικας εισόδου: μείωση του σηματοφόρου Κώδικας εξόδου: αύξηση του σηματοφόρου 6 lalis@inf.uth.gr
Κρίσιμο τμήμα με σηματοφόρους sem s; Pi: /* entry code */ i /* exit code */ 7 lalis@inf.uth.gr
πριν αρχίσει η εκτέλεση s? {? συμβολική (όχι απαραίτητα αυτή μιας πραγματικής υλοποίησης) τιμή ουρά αναμονής 8 lalis@inf.uth.gr
αρχικοποίηση σηματοφόρου με 1 s 1 { 9 lalis@inf.uth.gr
running ready ready εναλλαγή σε P0 s 1 { 10 lalis@inf.uth.gr
ready running ready εναλλαγή σε P1 s 1 { 11 lalis@inf.uth.gr
running ready ready εναλλαγή σε P0, P0 καλεί down, ο σηματοφόρος μειώνεται κατά 1 s 0 { 12 lalis@inf.uth.gr
running ready ready P0 εισέρχεται στο ΚΤ s 0 { 13 lalis@inf.uth.gr
ready running ready εναλλαγή σε P1 s 0 { 14 lalis@inf.uth.gr
ready waiting ready P1 καλεί down, ο σηματοφόρος έχει τιμή 0, P1 μπλοκάρεται μέσα στην down s 0 {P1 15 lalis@inf.uth.gr
ready waiting running εναλλαγή σε P2 s 0 {P1 16 lalis@inf.uth.gr
ready waiting waiting P2 καλεί down, ο σηματοφόρος έχει τιμή 0, P2 μπλοκάρεται μέσα στην down s 0 {P1,P2 17 lalis@inf.uth.gr
running waiting waiting εναλλαγή σε P0 s 0 {P1,P2 18 lalis@inf.uth.gr
running ready waiting P0 εξέρχεται από το ΚΤ, καλεί up, και βγάζει το P1 από την ουρά s 0 {P1,P2 19 lalis@inf.uth.gr
running ready waiting P0 συνεχίζει s 0 {P2 20 lalis@inf.uth.gr
running ready waiting P0 συνεχίζει s 0 {P2 21 lalis@inf.uth.gr
waiting ready waiting P0 καλεί down, ο σηματοφόρος έχει τιμή 0, P0 μπλοκάρεται μέσα στην down s 0 {P2,P0 22 lalis@inf.uth.gr
waiting running waiting εναλλαγή σε P1 s 0 {P2,P0 23 lalis@inf.uth.gr
waiting running waiting P1 εισέρχεται στο ΚΤ s 0 {P2,P0 24 lalis@inf.uth.gr
waiting running ready P1 εξέρχεται από το ΚΤ, καλεί up, και βγάζει το P2 από την ουρά s 0 {P2,P0 25 lalis@inf.uth.gr
waiting running ready P1 συνεχίζει s 0 {P0 26 lalis@inf.uth.gr
waiting ready running εναλλαγή σε P2 s 0 {P0 27 lalis@inf.uth.gr
waiting ready running P2 εισέρχεται στο ΚΤ s 0 {P0 28 lalis@inf.uth.gr
waiting running ready εναλλαγή σε P1 s 0 {P0 29 lalis@inf.uth.gr
waiting running ready P1 συνεχίζει s 0 {P0 30 lalis@inf.uth.gr
waiting waiting ready P1 καλεί down, ο σηματοφόρος έχει τιμή 0, P1 μπλοκάρεται μέσα στην down s 0 {P0,P1 31 lalis@inf.uth.gr
waiting waiting running P2 συνεχίζει s 0 {P0,P1 32 lalis@inf.uth.gr
ready waiting running P2 εξέρχεται από το ΚΤ, καλεί up, και βγάζει το P0 από την ουρά s 0 {P0,P1 33 lalis@inf.uth.gr
ready waiting running P2 συνεχίζει s 0 {P1 34 lalis@inf.uth.gr
running waiting ready εναλλαγή σε P0 s 0 {P1 35 lalis@inf.uth.gr
running waiting ready P0 εισέρχεται στο ΚΤ s 0 {P1 36 lalis@inf.uth.gr
running ready ready P0 εξέρχεται από το ΚΤ, καλεί up, και βγάζει το P1 από την ουρά s 0 {P1 37 lalis@inf.uth.gr
running ready ready P0 συνεχίζει s 0 { 38 lalis@inf.uth.gr
ready running ready εναλλαγή σε P1 s 0 { 39 lalis@inf.uth.gr
ready running ready το P1 εισέρχεται στο ΚΤ s 0 { 40 lalis@inf.uth.gr
ready running ready P1 εξέρχεται από το ΚΤ, καλεί up, και αυξάνει την τιμή του s κατά 1 s 1 { 41 lalis@inf.uth.gr
ready running ready P1 συνεχίζει την εκτέλεση του s 1 { 42 lalis@inf.uth.gr
«Χαμένες» κλήσεις της up Ένας δυαδικός σηματοφόρος παίρνει μόνο τιμές 0,1 Όταν η τιμή είναι 1 (δεν υπάρχουν νήματα που έχουν μπλοκάρει στην down), τυχόν επιπλέον κλήσεις της up δεν έχουν κανένα απολύτως αποτέλεσμα Η κλήση της up «χάνεται» Μια υλοποίηση μπορεί να επιτρέπει τέτοιες χαμένες κλήσεις, χωρίς να επιστρέφεται κωδικός λάθους Κώδικας σε επίπεδο εφαρμογής που μπορεί να οδηγεί σε χαμένες κλήσεις της up θεωρείται άκομψος και συνήθως πρόκειται για προγραμματιστικό λάθος 43 lalis@inf.uth.gr
Παράδειγμα: ραντεβού Το P1 πρέπει να περιμένει στο σημείο Α του κώδικα του, μέχρι το P2 να φτάσει στο σημείο Β του δικού του κώδικα Αυτό μπορεί να χρειαστεί να γίνει πολλές φορές P1 Α P2 Β Πως μπορεί να υλοποιηθεί ο επιθυμητός συγχρονισμός με δυαδικούς σηματοφόρους; σημείο ραντεβού 44 lalis@inf.uth.gr
bsem s; init(s,0); /* A */ /* B */ Σε ποια περίπτωση αυτή η λύση δεν είναι σωστή; Πως μπορεί να διορθωθεί το πρόβλημα; 45 lalis@inf.uth.gr