You are on page 1of 89

Σημαφόροι

(Σηματοφόροι / Σηματοφορείς)

Προγραμματισμός ΙΙΙ 1 lalis@inf.uth.gr


Σημαφόροι (semaphores)
• Ο σημαφόρος είναι ένας ΑΤΔ με πράξεις init, down
(wait, P) και up (signal, V).
• Η init(s,v) αρχικοποιεί τον σημαφόρο s με την
ακέραια τιμή v που πρέπει να είναι >=0.
• Η down(s) μειώνει την τιμή του σημαφόρου s κατά
ένα –αν η τιμή του s είναι =0, τότε το καλών νήμα
περιμένει μέχρι η τιμή του s να γίνει >0.
• Η up(s) αυξάνει την τιμή του σημαφόρου s κατά
ένα –ξεμπλοκάροντας ίσως ένα νήμα που επιχειρεί να
μειώσει την τιμή του s μέσω της down.
• Οι πράξεις down και up υλοποιούνται έτσι ώστε να
μπορεί να κληθούν ταυτόχρονα χωρίς πρόβλημα.

Προγραμματισμός ΙΙΙ 2 lalis@inf.uth.gr


Σημαφόροι και «δικαιοσύνη»
• Αν ένα ή περισσότερα νήματα έχουν μπλοκαριστεί
στην down και ένα νέο νήμα εκτελέσει την down
τότε μπλοκάρει και αυτό.
• ‘Οταν υπάρχουν πολλά νήματα μπλοκαρισμένα στην
down και εκτελεσθεί η up αφυπνίζεται ένα από αυτά
– random: η αφύπνιση γίνεται με τυχαία σειρά
– fair: η αφύπνιση γίνεται έτσι ώστε κανένα νήμα
να μην παραμείνει μπλοκαρισμένο απ’ άπειρο
– fifo: η αφύπνιση γίνεται με σειρά FIFO, δηλαδή με
την σειρά που τα νήματα κάλεσαν την down

Προγραμματισμός ΙΙΙ 3 lalis@inf.uth.gr


Τύποι σημαφόρων
• Δυαδικός σημαφόρος (binary semaphore) – μπορεί
να λάβει τιμές 0 ή 1.
• Γενικός σημαφόρος ή σημαφόρος μετρητής (general
/ counting semaphore) – μπορεί να λάβει τιμές >= 0.
• Οι δυαδικοί σημαφόροι (μπορεί να) έχουν
απλούστερη υλοποίηση καθώς χρειάζεται μόνο ένα bit
για να κρατά τις τιμές τους.
• Ένας γενικός σημαφόρος μπορεί να υλοποιηθεί με
βάση δυαδικούς σημαφόρους.

Προγραμματισμός ΙΙΙ 4 lalis@inf.uth.gr


Κρίσιμο τμήμα με σημαφόρους
sem s;
init(s,1);

Pi:
while (1) {

down(s); /* entry code */
do_critical_section();
up(s); /* exit code */

}

Προγραμματισμός ΙΙΙ 5 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


πριν αρχίσει η εκτέλεση
s ? {?}
τιμή
ουρά αναμονής
Προγραμματισμός ΙΙΙ 6 lalis@inf.uth.gr
sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


αρχικοποίηση σημαφόρου με
την τιμή 1 s 1 {}

Προγραμματισμός ΙΙΙ 7 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


αρχή εκτέλεσης P0
s 1 {}

Προγραμματισμός ΙΙΙ 8 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


αρχή εκτέλεσης P1
s 1 {}

Προγραμματισμός ΙΙΙ 9 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


προσπάθεια P0 να εισέλθει
στο ΚΤ, σημαφόρος μειώνεται s 0 {}
κατά 1

Προγραμματισμός ΙΙΙ 10 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


P0 μπαίνει στο ΚΤ
s 0 {}

Προγραμματισμός ΙΙΙ 11 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


προσπάθεια P1 να εισέλθει
στο ΚΤ, σημαφόρος έχει τιμή s 0 {P1}
0 επομένως P1 μπλοκάρεται

Προγραμματισμός ΙΙΙ 12 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


αρχή εκτέλεσης P2
s 0 {P1}

Προγραμματισμός ΙΙΙ 13 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


προσπάθεια P2 να εισέλθει
στο ΚΤ, σημαφόρος έχει τιμή s 0 {P1,P2}
0 επομένως P2 μπλοκάρεται

Προγραμματισμός ΙΙΙ 14 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


έξοδος P0 από το ΚΤ, οπότε
αφυπνίζεται το P1 (το οποίο s 0 {P2}
μπλόκαρε πριν το P2)

Προγραμματισμός ΙΙΙ 15 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


το P1 μπαίνει στο ΚΤ
s 0 {P2}

Προγραμματισμός ΙΙΙ 16 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


P0 εκτελεί κώδικα εκτός ΚΤ,
P1 παραμένει στο ΚΤ s 0 {P2}

Προγραμματισμός ΙΙΙ 17 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


P0 εκτελεί κώδικα εκτός ΚΤ,
έξοδος P1 από το ΚΤ, οπότε s 0 {}
αφυπνίζεται το P2

Προγραμματισμός ΙΙΙ 18 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


το P2 και μπαίνει στο ΚΤ
s 0 {}

Προγραμματισμός ΙΙΙ 19 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


P0+P1 εκτελούν κώδικα εκτός
ΚΤ, P2 είναι μέσα στο ΚΤ s 0 {}

Προγραμματισμός ΙΙΙ 20 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


P1 επιχειρεί να μπεί στο ΚΤ,
και μπλοκάρεται s 0 {P1}

Προγραμματισμός ΙΙΙ 21 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


P0 επιχειρεί να μπεί στο ΚΤ,
και μπλοκάρεται s 0 {P1,P0}

Προγραμματισμός ΙΙΙ 22 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


έξοδος P2 από το ΚΤ, οπότε
αφυπνίζεται το P1 s 0 {P0}

Προγραμματισμός ΙΙΙ 23 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


το P1 και εισέρχεται στο ΚΤ
s 0 {P0}

Προγραμματισμός ΙΙΙ 24 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


P2 συνεχίζει την εκτέλεση του
s 0 {P0}

Προγραμματισμός ΙΙΙ 25 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


έξοδος P1 από το ΚΤ, οπότε
αφυπνίζεται το P0 s 0 {}

Προγραμματισμός ΙΙΙ 26 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


το P0 και εισέρχεται στο ΚΤ
s 0 {}

Προγραμματισμός ΙΙΙ 27 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


P1 συνεχίζει την εκτέλεση του
s 0 {}

Προγραμματισμός ΙΙΙ 28 lalis@inf.uth.gr


sem s;
init(s,1);

P0: P1: P2:


while (1) { while (1) { while (1) {
down(s); down(s); down(s);
do_CS(); do_CS(); do_CS();
up(s); up(s); up(s);
… … …
} } }

Σχόλιο Κατάσταση σημαφόρου


έξοδος P0 από το ΚΤ, και
αφού κανένα νήμα δεν s 1 {}
περιμένει στον σημαφόρο,
αυξάνεται η τιμή του κατά 1
Προγραμματισμός ΙΙΙ 29 lalis@inf.uth.gr
Προσοχή!
• Ένας δυαδικός σημαφόρος παίρνει τιμές 0,1.
• Αν δεν υπάρχουν νήματα μπλοκαρισμένα στην down,
και η τιμή του σημαφόρου είναι ήδη 1, τυχόν κλήσεις
της up δεν έχουν κανένα αποτέλεσμα, και η τιμή
του σημαφόρου παραμένει 1.
• Αν θέλουμε να μην «χάνονται» οι κλήσεις της up
όταν δεν υπάρχουν μπλοκαρισμένα νήματα στην
down, χρησιμοποιούμε γενικό σημαφόρο.

Προγραμματισμός ΙΙΙ 30 lalis@inf.uth.gr


Παράδειγμα
• Δίνονται 3 νήματα P0, P1 και P2.
• Έστω ότι πρέπει να υλοποιηθεί ένα «σημείο»
συγχρονισμού ανάμεσα στα νήματα ως εξής:
• Αν το P0 φτάσει στο σημείο Α του κώδικα του πριν
το P1 φτάσει στο σημείο Β του κώδικα του ή/και πριν
το P2 φτάσει στο σημείο Γ του κώδικα του, τότε το
P0 μπορεί να συνεχίσει την εκτέλεση του.
• Αν το P1 φτάσει στο σημείο Β του κώδικα του πριν
το P0 φτάσει στο σημείο Α του κώδικα του, τότε το
P1 πρέπει να περιμένει.
• Αν το P2 φτάσει στο σημείο Γ του κώδικα του πριν
το P0 φτάσει στο σημείο Α του κώδικα του, τότε το
P2 πρέπει να περιμένει.
Προγραμματισμός ΙΙΙ 31 lalis@inf.uth.gr
sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


αρχικοποίηση σημαφόρου με
την τιμή 0 s 0 {}

Προγραμματισμός ΙΙΙ 32 lalis@inf.uth.gr


sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


P0 εκτελεί up και αυξάνει την
τιμή κατά 1 s 1 {}

Προγραμματισμός ΙΙΙ 33 lalis@inf.uth.gr


sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


P0 εκτελεί up (ξανά!) αλλά η
τιμή παραμένει 1 s 1 {}

Προγραμματισμός ΙΙΙ 34 lalis@inf.uth.gr


sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


P0 συνεχίζει την εκτέλεση του
s 1 {}

Προγραμματισμός ΙΙΙ 35 lalis@inf.uth.gr


sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


P1 εκτελεί down και μειώνει
την τιμή κατά 1 s 0 {}

Προγραμματισμός ΙΙΙ 36 lalis@inf.uth.gr


sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


P1 συνεχίζει την εκτέλεση του
s 0 {}

Προγραμματισμός ΙΙΙ 37 lalis@inf.uth.gr


sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


P2 εκτελεί down και
μπλοκάρεται … επ’ αόριστο! s 0 {P2}

Προγραμματισμός ΙΙΙ 38 lalis@inf.uth.gr


Σχόλιο
• Η προηγούμενη εκτέλεση αντιστοιχεί σε ένα από τα
διάφορα πιθανά σενάρια ταυτόχρονης εκτέλεσης.
• Υπάρχουν άλλα σενάρια όπου
– το P2 δεν μπλοκάρει, αλλά μπλοκάρει το P1
– δεν μπλοκάρει ούτε το P1 ούτε το P2
• Το αποτέλεσμα εξαρτάται από την εναλλαγή των
διαφόρων νημάτων.
• Καθώς δεν μπορούμε να ελέγξουμε την εναλλαγή, το
παραπάνω πρόγραμμα έχει μη ντετερμινιστική
συμπεριφορά.
• Η λύση είναι να χρησιμοποιήσουμε γενικό σημαφόρο.

Προγραμματισμός ΙΙΙ 39 lalis@inf.uth.gr


sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


αρχικοποίηση σημαφόρου με
την τιμή 0 s 0 {}

Προγραμματισμός ΙΙΙ 40 lalis@inf.uth.gr


sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


P0 εκτελεί up και αυξάνει την
τιμή κατά 1 s 1 {}

Προγραμματισμός ΙΙΙ 41 lalis@inf.uth.gr


sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


P0 εκτελεί up (ξανά!) και
αυξάνει την τιμή κατά 1 s 2 {}

Προγραμματισμός ΙΙΙ 42 lalis@inf.uth.gr


sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


P0 συνεχίζει την εκτέλεση του
s 2 {}

Προγραμματισμός ΙΙΙ 43 lalis@inf.uth.gr


sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


P1 εκτελεί down και μειώνει
την τιμή κατά 1 s 1 {}

Προγραμματισμός ΙΙΙ 44 lalis@inf.uth.gr


sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


P1 συνεχίζει την εκτέλεση του
s 1 {}

Προγραμματισμός ΙΙΙ 45 lalis@inf.uth.gr


sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


P2 εκτελεί down και μειώνει
την τιμή κατά 1 s 0 {}

Προγραμματισμός ΙΙΙ 46 lalis@inf.uth.gr


sem s;
init(s,0);

P0: P1: P2:


… … …
up(s); down(s); down(s);
up(s); … …

Σχόλιο Κατάσταση σημαφόρου


όλα τα νήματα συνεχίζουν
την εκτέλεση τους s 0 {}

Προγραμματισμός ΙΙΙ 47 lalis@inf.uth.gr


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

Προγραμματισμός ΙΙΙ 48 lalis@inf.uth.gr


Υλοποίηση δυαδικών / γενικών σημαφόρων
• Ένας σημαφόρος είναι ένας ακέραιος μαζί με μια ουρά
αναμονής όπου τοποθετείται ένα νήμα όταν
επιχειρήσει να μειώσει την τιμή του ακεραίου και η
τιμή του είναι ήδη 0.
• Οι λειτουργίες down/up εκτελούν «ατομικές» πράξεις
στον ακέραιο και την ουρά.
• Οι πράξεις down/up μπορεί να υλοποιηθούν με
ενεργή αναμονή.
• Οι πράξεις down/up μπορεί να υλοποιηθούν με βάση
τις πράξεις suspend/resume.

Προγραμματισμός ΙΙΙ 49 lalis@inf.uth.gr


typedef struct bs {
int locked; /* αμοιβαίος αποκλεισμός */
int val; /* τιμή σημαφόρου */
} bsem;

void init(bsem *s, int val) {


s->locked=0; s->val=val;
}

void down(bsem *s) {


int done=0;
do {
while (TAS(&s->locked));
if (s->val>0) {s->val=0; done=1;}
s->locked=0;
} while (!done);
}

void up(bsem *s) {


s->val=1;
}
Προγραμματισμός ΙΙΙ 50 lalis@inf.uth.gr
typedef struct bs {
int val; /* τιμή σημαφόρου */
} bsem;

void init(bsem *s, int val) {


s->val=val;
}

void down(bsem *s) {


beg_atomic();
while (s->val == 0) {yield();}
s->val=0;
end_atomic();
}

void up(bsem *s) {


s->val=1;
}

Προγραμματισμός ΙΙΙ 51 lalis@inf.uth.gr


typedef struct bs {
Queue q;
int v;
} bsem;

void init(bsem *s, int v) {


queue_init(&s->q);
s->v=v;
}

void down(bsem *s) {


beg_atomic();
if (s->v==0) {suspend(&s->q);}
else {s->v=0;}
end_atomic();
}

void up(bsem *s) {


beg_atomic();
if (!queue_empty(&s->q) {resume(&s->q);}
else {s->v=1;}
end_atomic();
}
Προγραμματισμός ΙΙΙ 52 lalis@inf.uth.gr
typedef struct gs {
Queue q;
int v;
} gsem;

void init(gsem *s, int v) {


queue_init(&s->q);
s->v=v;
}

void down(gsem *s) {


beg_atomic();
if (s->v==0) {suspend(&s->q);}
else {s->v--;}
end_atomic();
}

void up(gsem *s) {


beg_atomic();
if (!queue_empty(&s->q) {resume(&s->q);}
else {s->v++;}
end_atomic();
}
Προγραμματισμός ΙΙΙ 53 lalis@inf.uth.gr
Σχόλιο
• Η υλοποίηση των δυαδικών ή γενικών σημαφόρων
γίνεται συνήθως από το ίδιο το λειτουργικό σύστημα.
• Εκεί υλοποιείται και ο μηχανισμός εναλλαγής
νημάτων, οπότε υπάρχει ακριβής έλεγχος του.
• Μπορούν να γίνουν επιπλέον βελτιστοποιήσεις,
π.χ. κατάλληλη δομή διεργασίας έτσι ώστε η
προσθήκη σε και απομάκρυνση από μια ουρά
αναμονής να μπορούν να υλοποιηθούν αποδοτικά.
• Σπάνια ένα (λειτουργικό) σύστημα δίνει την
δυνατότητα στον προγραμματιστή (εφαρμογών)
να απενεργοποιήσει την εναλλαγή.

Προγραμματισμός ΙΙΙ 54 lalis@inf.uth.gr


Γενικοί σημαφόροι με δυαδικούς
• Μπορούμε να υλοποιήσουμε γενικούς σημαφόρους
χρησιμοποιώντας δυαδικούς σημαφόρους.
• Χρησιμοποιούμε (α) ένα δυαδικό σημαφόρο mtx για
αμοιβαίο αποκλεισμό για την πρόσβαση στα δεδομένα
του σημαφόρου, και (β) ένα δυαδικό σημαφόρο q
που χρησιμοποιούμε σαν ουρά αναμονής.
• Η αναμονή στην ουρά (σημαφόρο q) γίνεται στην
down όταν η τιμή του σημαφόρου είναι 0.
• Πριν το καλών νήμα μπλοκάρει στον σημαφόρο q,
πρέπει να αυξήσει τον σημαφόρο mtx έτσι ώστε ένα
άλλο νήμα να μπορέσει (κάποια στιγμή) να εκτελέσει
τον κώδικα της up, και να το αφυπνίσει.

Προγραμματισμός ΙΙΙ 55 lalis@inf.uth.gr


typedef struct gs {
int val,qlen; /* μετρητής, μέγεθος ουράς */
bsem mtx,q; /* προστασία πρόσβασης, ουρά */
} gsem;

void init(gsem *s, int val) {


s->val=val; s->qlen=0;
binit(&s->mtx,1); binit(&s->q,0);
}

void down(sem *s) {


bdown(&s->mtx);
if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
}

void up(sem *s) {


bdown(&s->mtx);
if (s->qlen == 0) {s->val++;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
}
Προγραμματισμός ΙΙΙ 56 lalis@inf.uth.gr
Πρόβλημα A
• Υπάρχει περίπτωση προσπεράσματος με ταυτόχρονη
εκτέλεση της down.
• Aφού το νήμα P0 αυξήσει τον σημαφόρο s->mxt
(δηλαδή ελευθερώσει την είσοδο στην down) και
πριν προλάβει να μειώσει τον σημαφόρο s->q
(δηλαδή να τοποθετηθεί στην ουρά), μπορεί να
προσπεραστεί από ένα άλλο νήμα P1.
• Παρ’ όλα αυτά, ο επ’ άπειρο παραγκωνισμός του
νήματος P0 είναι απίθανος --γιατί;

Προγραμματισμός ΙΙΙ 57 lalis@inf.uth.gr


typedef struct gs {
int val,qlen; /* μετρητής, μέγεθος ουράς */
bsem mtx,q; /* προστασία πρόσβασης, ουρά */
} gsem;

void init(sem *s, int val) {


s->val=val; s->qlen=0;
binit(&s->mtx,1); binit(&s->q,0);
}

void down(sem *s) {


bdown(&s->mtx);
if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
}

void up(sem *s) {


bdown(&s->mtx);
if (s->qlen == 0) {s->val++;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
}
Προγραμματισμός ΙΙΙ 58 lalis@inf.uth.gr
Πρόβλημα B
• Επιπλέον υπάρχει περίπτωση ασυνέπειας με
ταυτόχρονη εκτέλεση των down και up.
• Δύο (ή περισσότερα) νήματα μπορεί να φτάσουν και
να διακοπεί η εκτέλεση τους στο σημείο της
προσπέρασης, και στη συνέχει να εκτελεσθεί δύο
(ή περισσότερες) φορές η up.
• Το αποτέλεσμα είναι ότι θα «χαθεί» μια κλήση (ή
περισσότερες κλήσεις) up στον σημαφόρο s->q
(αφύπνιση από την ουρά) και ένα ή περισσότερα
νήματα θα μείνουν μπλοκαρισμένα στην down.
• Είναι μια περίπτωση συνθήκης ανταγωνισμού.

Προγραμματισμός ΙΙΙ 59 lalis@inf.uth.gr


Παράδειγμα Κατάσταση σημαφόρου
s->val = ?, s->qlen = ?
sem s; s->mtx ? {?}
init(s,0); s->q ? {?}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 60 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 0
sem s; s->mtx 1 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 61 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 0
sem s; s->mtx 1 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 62 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 0
sem s; s->mtx 0 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 63 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 0
sem s; s->mtx 0 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 64 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 1
sem s; s->mtx 0 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 65 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 1
sem s; s->mtx 1 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 66 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 1
sem s; s->mtx 1 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 67 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 1
sem s; s->mtx 0 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 68 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 1
sem s; s->mtx 0 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 69 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 2
sem s; s->mtx 0 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 70 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 2
sem s; s->mtx 1 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 71 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 2
sem s; s->mtx 1 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 72 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 2
sem s; s->mtx 0 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 73 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 2
sem s; s->mtx 0 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 74 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 1
sem s; s->mtx 0 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 75 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 1
sem s; s->mtx 0 {}
init(s,0); s->q 1 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 76 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 1
sem s; s->mtx 1 {}
init(s,0); s->q 1 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 77 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 1
sem s; s->mtx 1 {}
init(s,0); s->q 1 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 78 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 1
sem s; s->mtx 0 {}
init(s,0); s->q 1 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 79 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 1
sem s; s->mtx 0 {}
init(s,0); s->q 1 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 80 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 0
sem s; s->mtx 0 {}
init(s,0); s->q 1 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 81 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 0
sem s; s->mtx 0 {}
init(s,0); s->q 1 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;} «χάνεται»!
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 82 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 0
sem s; s->mtx 1 {}
init(s,0); s->q 1 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 83 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 0
sem s; s->mtx 1 {}
init(s,0); s->q 0 {}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 84 lalis@inf.uth.gr
bup(&s->mtx);
Παράδειγμα Κατάσταση σημαφόρου
s->val = 0, s->qlen = 0
sem s; s->mtx 1 {}
init(s,0); s->q 0 {P0}

P0: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P1: bdown(&s->mtx);
down(s) if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
P2: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
P3: bdown(&s->mtx);
up(s) if (s->qlen == 0) {s->val=1;}
else {s->qlen--; bup(&s->q);}
Προγραμματισμός ΙΙΙ 85 lalis@inf.uth.gr
bup(&s->mtx);
Το πρόβλημα
• Το πρόβλημα είναι ότι αίρεται ο αμοιβαίος
αποκλεισμός στην down πριν ένα νήμα προλάβει να
μπλοκάρει στην ουρά αναμονής q.
• Αυτό πρέπει αναγκαστικά να γίνει έτσι ώστε να
επιτρέψουμε σε κάποιο άλλο νήμα να εκτελέσει
κάποια στιγμή την up και να αφυπνίσει τα νήματα
που περιμένουν στην q.
• Έτσι όμως επιτρέπουμε και σε άλλα νήματα να
εκτελέσουν την down «μερικώς», και να αυξήσουν
την τιμή qlen χωρίς να υπάρχει ούτε ένα νήμα που
περιμένει στον σημαφόρο q.

Προγραμματισμός ΙΙΙ 86 lalis@inf.uth.gr


Λύση
• Πρέπει να απαγορέψουμε σε παραπάνω από ένα
νήματα να αυξήσουν την τιμή της qlen.
• Χρειαζόμαστε ένα ακόμα δυαδικό σημαφόρο q2, που
χρησιμοποιούμε για αμοιβαίο αποκλεισμό μεταξύ των
νημάτων που καλούν την down.
• Ουσιαστικά, η ουρά αναμονής που υλοποιούσαμε
μέσω του σημαφόρου q σπάει στα δύο, με το πρώτο
νήμα να μπλοκάρει στον q και όλα τα υπόλοιπα
νήματα που καλούν down «ταυτόχρονα» να
μπλοκάρουν στον σημαφόρο q2.

Προγραμματισμός ΙΙΙ 87 lalis@inf.uth.gr


typedef struct gs {
int val,qlen;
bsem mtx,q,q2; /* …, σειριοποίηση στην down */
} gsem;
void init(sem *s, int val) {
s->val=val; s->qlen=0;
binit(&s->mtx,1); binit(&s->q,0); binit(&s->q2,1);
}
void down(sem *s) {
bdown(&s->q2);
bdown(&s->mtx);
if (s->val > 0) {s->val--; bup(&s->mxt);}
else {s->qlen++; bup(&s->mtx); bdown(&s->q);}
bup(&s->q2);
}
void up(sem *s) {
bdown(&s->mtx);
if (s->qlen == 0) {s->val++;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
}
Προγραμματισμός ΙΙΙ 88 lalis@inf.uth.gr
typedef struct gs {
int val,qlen;
bsem mtx,q,q2; /* …, σειριοποίηση στην down */
} gsem;
void init(sem *s, int val) {
s->val=val; s->qlen=0;
binit(&s->mtx,1); binit(&s->q,0); binit(&s->q2,1);
}
void down(sem *s) {
bdown(&s->mtx);
if (s->val > 0) {s->val--; bup(&s->mxt);}
else {
bdown(&s->q2);
s->qlen++; bup(&s->mtx); bdown(&s->q);
bup(&s->q2);
}
}
void up(sem *s) {
bdown(&s->mtx);
if (s->qlen == 0) {s->val++;}
else {s->qlen--; bup(&s->q);}
bup(&s->mtx);
}Προγραμματισμός ΙΙΙ 89 lalis@inf.uth.gr

You might also like