Ορθότητα λειτουργίας τμημάτων λογισμικού & δομών δεδομένων υπό ταυτόχρονη εκτέλεση ΙΙΙ 1 lalis@inf.uth.gr
Ορθή συμπεριφορά τμήματος λογισμικού Ένα τμήμα λογισμικού (ή ένας ΑΤΔ) προσπελάζεται με δομημένο/ελεγχόμενο τρόπο, μέσα από συγκεκριμένες λειτουργίες / πράξεις πρόσβασης Υποθέτοντας μονονηματική/σειριακή εκτέλεση, η επιθυμητή λειτουργικότητα ορίζεται με βάση μια αντικειμενική παρατήρηση της συμπεριφοράς Μια υλοποίηση είναι ορθή/σωστή αν επιτυγχάνει την προσδιορισμένη επιθυμητή λειτουργικότητα (χωρίς να γνωρίζουμε το πως τα καταφέρνει) ΙΙΙ 2 lalis@inf.uth.gr
Ουρά FIFO init(): αρχικοποίηση put(object o): προσθήκη Object get(): αφαίρεση βοηθητική συνάρτηση ISEMPTY() get put init FIFO_Queue 1) init(); ISEMPTY() 2) ISEMPTY() ο=get(); ο == NULL ISEMPTY() μια «τυπική» περιγραφή της ορθής λειτουργίας 3) ISEMPTY() put(x1); put(xn); ο1=get(); οn=get(); o1 == x1 οn == xn ISEMPTY() ΙΙΙ 3 lalis@inf.uth.gr
Ζητούμενο Υποθέτουμε ότι η επιθυμητή λειτουργικότητα έχει προσδιοριστεί για μια σειριακή εκτέλεση Θέλουμε να φτιάξουμε μια υλοποίηση που μπορεί να χρησιμοποιηθεί υπό ταυτόχρονη εκτέλεση Ποιες «συμπεριφορές» είναι επιτρεπτές υπό ταυτόχρονη εκτέλεση; Πως μπορούμε να σκεφτούμε για αυτές, έτσι ώστε να βρούμε τα περιθώρια που (τυχόν) υπάρχουν σε επίπεδο υλοποίησης; ΙΙΙ 4 lalis@inf.uth.gr
Μοντέλο εκτέλεσης Οι λειτουργίες/πράξεις πρόσβασης θεωρούνται μηακαριαίες Κάθε πράξη πρόσβασης «σπάει» σε δύο μέρη: (1) αίτηση/κλήση, (2) απάντηση/επιστροφή Το διάστημα ανάμεσα στην αίτηση και την απάντηση αντιστοιχεί στην διάρκεια εκτέλεσης της πράξης Ταυτόχρονη εκτέλεση: χρονική επικάλυψη των πράξεων πρόσβασης που εκτελούν τα νήματα ΙΙΙ 5 lalis@inf.uth.gr
Συμβολισμοί op(x,y)p πράξη op, καλείται από το νήμα P με παραμέτρους x και επιστρέφει αποτελέσματα y P op(x) t1 OK(y) t2 η εκτέλεση της op(x,y)p αρχίζει και ολοκληρώνεται τις χρονικές στιγμές t1 και t2 αντίστοιχα ΙΙΙ 6 lalis@inf.uth.gr
Σειρά εκτέλεσης Η πράξη op2(x2,y2) εκτελείται μετά την πράξη op1(x1,y1) αν ισχύει ότι: ΟΚ(y1),,op2(x2) Χρησιμοποιούμε τον συμβολισμό: op1 op2 Η πράξη op2(x2,y2) εκτελείται ταυτόχρονα με την πράξη op1(x1,y1) αν ισχύει ότι: op1(x1),,op2(x2),,ok(y1) ή op2(x1),,op1(x2),,ok(y2) Χρησιμοποιούμε τον συμβολισμό: op1 op2 ΙΙΙ 7 lalis@inf.uth.gr
op1(x1) ΟΚ(y1) op1 op2 (1) op2(x2) ΟΚ(y2) op1(x1) ΟΚ(y1) op1 op2 (2) op2(x2) ΟΚ(y2) op1(x1) ΟΚ(y1) op1 op2 (3) op2(x2) ΟΚ(y2) ΙΙΙ 8 lalis@inf.uth.gr
Ιστορία εκτέλεσης Καταγραφή των πράξεων που γίνονται στον χρόνο Δύο τύποι «γεγονότων»: αιτήσεις και απαντήσεις Ιστορία: ακολουθία γεγονότων που αντιστοιχεί σε μια (αυστηρά σειριακή ή ταυτόχρονη) εκτέλεση Η σειρά των γεγονότων αντιστοιχεί στην χρονική στιγμή «αποστολής» των αιτήσεων op(x)p, και «παραλαβής» των απαντήσεων OK(y)P Κανόνες τοπικής ιστορίας κάθε νήματος: το αποτέλεσμα μιας πράξης εμφανίζεται μετά την αίτηση η επόμενη αίτηση στέλνεται αφού παραληφθεί η απάντηση για την προηγούμενη αίτηση (σειριακή εκτέλεση πράξεων) ΙΙΙ 9 lalis@inf.uth.gr
Σειριακή και ταυτόχρονη ιστορία Σειριακή (καθολική) ιστορία: δεν υπάρχει χρονική επικάλυψη μεταξύ των πράξεων που εκτελούν διαφορετικά νήματα Κάθε αίτηση op(x)p ακολουθείται από την αντίστοιχη απάντηση OK(y)P χωρίς να μεσολαβεί κάποια άλλη αίτηση ή απάντηση Ταυτόχρονη (καθολική) ιστορία: υπάρχει επικάλυψη ανάμεσα στις πράξεις που γίνονται μέσα από διαφορετικά νήματα Υπάρχει op(x)p και OK(y)P ανάμεσα στις οποίες παρεμβάλλεται μια άλλη αίτηση op(x) ΙΙΙ 10 lalis@inf.uth.gr
Σειριακή εκτέλεση op1(x1) ΟΚ(y1) op2(x2) ΟΚ(y2) op3(x3) ΟΚ(y3) σειριακή ιστορία op2(x2), OK(y2), op1(x1), OK(y1), op3(x3), OK(y3) ΙΙΙ 11 lalis@inf.uth.gr
Ταυτόχρονη εκτέλεση op1(x1) ΟΚ(y1) op2(x2) ΟΚ(y2) op3(x3) ΟΚ(y3) ταυτόχρονη ιστορία op2(x2), op1(x1), OK(y2), op3(x3), OK(y1), OK(y3) ΙΙΙ 12 lalis@inf.uth.gr
Ορθή σειριακή εκτέλεση Κάθε σειριακή εκτέλεση αντιστοιχεί σε μια μοναδική σειριακή ιστορία Επιτρεπτή σειριακή ιστορία: το αποτέλεσμα των πράξεων είναι συμβατό με τις προδιαγραφές (δεν αντιφάσκουν με την επιθυμητή λειτουργικότητα) Ορθή σειριακή εκτέλεση: η αντίστοιχη σειριακή ιστορία είναι επιτρεπτή ΙΙΙ 13 lalis@inf.uth.gr
FIFO Queue put(a) ΟΚ() get() ΟΚ(b) put(b) ΟΚ() get() OK(a) επιτρεπτή σειριακή ιστορία put(a), OK(), put(b), OK(), get(), OK(a), get(), OK(b) ΙΙΙ 14 lalis@inf.uth.gr
FIFO Queue put(a) ΟΚ() get() ΟΚ(a) put(b) ΟΚ() get() OK(b) μη επιτρεπτή σειριακή ιστορία put(a), OK(), put(b), OK(), get(), OK(b), get(), OK(a) ΙΙΙ 15 lalis@inf.uth.gr
Σειριακή ισοδυναμία Μια ταυτόχρονη ιστορία Ι είναι ισοδύναμη με την σειριακή ιστορία Ι αν: 1. Οι πράξεις που έχουν συγκεκριμένη σχετική σειρά στην Ι, έχουν την ίδια σχετική σειρά και στην Ι op1 op2 Ι op1 op2 Ι 2. Οι πράξεις που είναι ταυτόχρονες στην Ι, έχουν μια (οποιαδήποτε) σχετική σειρά στην Ι op1 op2 Ι op1 op2 Ι op2 op1 Ι Μια ταυτόχρονη ιστορία Ι έχει πολλές διαφορετικές ισοδύναμες σειριακές ιστορίες Ι ΙΙΙ 16 lalis@inf.uth.gr
Διαδικασία «κατασκευής» Θεωρούμε ότι κάθε πράξη εκτελείται στιγμιαία (αίτηση και απάντηση συμπίπτουν στον χρόνο) Επιλέγουμε ελεύθερα την χρονική στιγμή εκτέλεσης κάθε πράξης, αρκεί αυτή: (α) να βρίσκεται μέσα στο αρχικό διάστημα εκτέλεσης της πράξης (β) να μην συμπίπτει με κάποια άλλη πράξη Κάθε τέτοιο σενάριο αντιστοιχεί σε μια σειριακή εκτέλεση που είναι ισοδύναμη με την ταυτόχρονη ΙΙΙ 17 lalis@inf.uth.gr
op1(x1) ΟΚ(y1) op2(x2) ΟΚ(y2) op3(x3) ΟΚ(y3) P3 op4(x4) ΟΚ(y4) ΙΙΙ 18 lalis@inf.uth.gr
ισοδύναμη σειριακή εκτέλεση op1(x1) ΟΚ(y1) op2(x2) ΟΚ(y2) op3(x3) ΟΚ(y3) P3 op4(x4) ΟΚ(y4) op4 op2 op1 op3 ΙΙΙ 19 lalis@inf.uth.gr
ισοδύναμη σειριακή εκτέλεση op1(x1) ΟΚ(y1) op2(x2) ΟΚ(y2) op3(x3) ΟΚ(y3) P3 op4(x4) ΟΚ(y4) op2 op1 op3 op4 ΙΙΙ 20 lalis@inf.uth.gr
μη ισοδύναμη σειριακή εκτέλεση op1(x1) ΟΚ(y1) op2(x2) ΟΚ(y2) op3(x3) ΟΚ(y3) P3 op4(x4) ΟΚ(y4) op2 op4 op3 op1 ΙΙΙ 21 lalis@inf.uth.gr
Παρατήρηση Η σχετική σειρά των πράξεων που εκτελούνται σειριακά (στην ταυτόχρονη εκτέλεση) δεν μπορεί να αλλάξει Πιθανώς είναι αποτέλεσμα ρητού (αλλά μη ορατού σε εμάς) συγχρονισμού ανάμεσα στα νήματα Συνεπώς δεν έχουμε «δικαίωμα» να αλλάξουμε την σχετική σειρά αυτών των πράξεων Ουσιαστική ελευθερία επιλογής υπάρχει μόνο ως προς τις ταυτόχρονες (επικαλυπτόμενες) πράξεις Δεν υπάρχει λογική εξάρτηση μεταξύ τους σε επίπεδο εφαρμογής (εκτός αν η εφαρμογή έχει bug) Έχουμε «δικαίωμα» να τις διατάξουμε όπως θέλουμε ΙΙΙ 22 lalis@inf.uth.gr
op1(x1) συγχρονισμός μεταξύ και ΟΚ(y1) παραβίαση λογικής συνέπειας op2(x2) ΟΚ(y2) op3(x3) ΟΚ(y3) P3 op4(x4) ΟΚ(y4) ΙΙΙ 23 lalis@inf.uth.gr
Ορθότητα Μια ταυτόχρονη εκτέλεση είναι ορθή (επιτρεπτή) αν είναι ισοδύναμη με (μπορεί να αντιστοιχηθεί σε) τουλάχιστον μια ορθή σειριακή εκτέλεση ΙΙΙ 24 lalis@inf.uth.gr
FIFO Queue put(a) ΟΚ() get() ΟΚ(a) επιτρεπτή ΙΙΙ 25 lalis@inf.uth.gr
FIFO Queue put(a) ΟΚ() get() ΟΚ(NULL) επιτρεπτή ΙΙΙ 26 lalis@inf.uth.gr
FIFO Queue put(a) ΟΚ() get() ΟΚ(a) επιτρεπτή ΙΙΙ 27 lalis@inf.uth.gr
FIFO Queue put(a) ΟΚ() get() ΟΚ(NULL) επιτρεπτή ΙΙΙ 28 lalis@inf.uth.gr
FIFO Queue put(a) ΟΚ() get() ΟΚ(b) put(b) ΟΚ() μη επιτρεπτή ΙΙΙ 29 lalis@inf.uth.gr
FIFO Queue put(a) ΟΚ() get() ΟΚ(b) put(b) ΟΚ() get() OK(a) επιτρεπτή ΙΙΙ 30 lalis@inf.uth.gr
FIFO Queue put(a) ΟΚ() get() ΟΚ(a) put(b) ΟΚ() get() OK(b) επιτρεπτή ΙΙΙ 31 lalis@inf.uth.gr
FIFO Queue put(a) ΟΚ() get() ΟΚ(a) put(b) ΟΚ() get() OK(a) μη επιτρεπτή ΙΙΙ 32 lalis@inf.uth.gr
Έλεγχος ταυτόχρονης εκτέλεσης Καταγράφουμε την ιστορία της ταυτόχρονης εκτέλεσης Αν βρούμε έστω και μια επιτρεπτή σειριακή ιστορία που είναι ισοδύναμη με την ταυτόχρονη ιστορία, τότε η (συγκεκριμένη) εκτέλεση είναι επιτρεπτή όπως ξέρουμε, αυτό δεν λέει πολλά για την ορθότητα... Αν ελέγξουμε όλες τις ισοδύναμες σειριακές ιστορίες και καμία από αυτές δεν είναι επιτρεπτή, τότε η εκτέλεση είναι λανθασμένη είναι σίγουρο ότι η υλοποίηση είναι προβληματική ΙΙΙ 33 lalis@inf.uth.gr
Αποφυγή σειροποίησης Η απλούστερη σωστή υλοποίηση είναι αυτή όπου τα πάντα γίνονται υπό αμοιβαίο αποκλεισμό σειριοποίηση των λειτουργιών πρόσβασης Αυτό μπορεί να μην είναι καλό για την απόδοση ιδίως σε συστήματα με πολλούς επεξεργαστές Ιδανικά θα θέλαμε κάποια τμήματα του κώδικα των πράξεων πρόσβασης να εκτελούνται ταυτόχρονα, χωρίς να προκύπτουν προβλήματα ορθότητας Π.χ., αυτό μπορεί να γίνει για λειτουργίες που εμπίπτουν στο πνεύμα των readers-writers ΙΙΙ 34 lalis@inf.uth.gr