ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ
ΘΕΩΡΙΑ
ΘΕΩΡΙΑ
4: Συνθήκες Συναγωνισμού, Συγχρονισμός, Αδιέξοδα
- Κοινοχρησία Πόρων και Συνθήκες Συναγωνισμού (Race Conditions):
oΌταν πολλαπλές διεργασίες επιχειρούν να προσπελάσουν ταυτοχρόνως κάποιον κοινό υπολογιστικό πόρο δημιουργούνται οι λεγόμενες συνθήκες συναγωνισμού.
oΟ κοινός πόρος μπορεί να είναι κάποια περιφερειακή συσκευή (π.χ. ένας εκτυπωτής), ένα τμήμα δεδομένων στη μνήμη (π.χ. αν έχει ζητηθεί από τον πυρήνα η παροχή κοινής μνήμης για διαδιεργασιακή επικοινωνία) κλπ.
oΟι συνθήκες συναγωνισμού δεν συνεπάγονται ότι απαραιτήτως θα συμβεί κάποιο σφάλμα εξαιτίας της ταυτόχρονης (παράλληλης ή ψευδοπαράλληλης) προσπέλασης, αλλά ότι υπάρχουν οι συνθήκες για να εμφανιστεί σφάλμα συνέπειας υπό κατάλληλες προϋποθέσεις. Η έλλειψη συνέπειας σημαίνει πως μία διεργασία νομίζει πως ισχύει κάτι, ενώ στην πραγματικότητα δεν ισχύει λόγω της συμπτωματικής παρεμβολής μίας άλλης διεργασίας. Επομένως, υπό συνθήκες συναγωνισμού, το τελικό αποτέλεσμα της εκτέλεσης ενός προγράμματος εξαρτάται με απρόοπτο και φαινομενικά τυχαίο τρόπο από τη χρονική αλληλουχία με την οποία συμβαίνουν μία σειρά από υπολογιστικά γεγονότα.
oΟ προγραμματιστής των εφαρμογών πρέπει να έχει λάβει τα μέτρα του, συγγράφοντας κατάλληλο, ασφαλή κώδικα. Σε ορισμένες περιπτώσεις αυτό το κάνουν τα ίδια τα λειτουργικά συστήματα (π.χ. ίσως να σειριοποιούν αυτομάτως την πρόσβαση στον εκτυπωτή, αναθέτοντας προτεραιότητες στις διεργασίες που επιχειρούν να τον προσπελάσουν).
oΤα σημεία του κώδικα ενός προγράμματος τα οποία προσπελαύνουν κάποιον κοινό πόρο ονομάζονται κρίσιμα σημεία ή κρίσιμος κώδικας.
- Παράδειγμα (Μέρος 1ο):
oΈστω δύο διεργασίες, Α και Β, οι οποίες γράφουν και διαβάζουν μία μεταβλητή ονόματι «c» τοποθετημένη σε κοινή μνήμη. Η κοινή μνήμη είναι ένας μηχανισμός διαδιεργασιακής επικοινωνίας που παρέχεται από τον πυρήνα μέσω κατάλληλων κλήσεων συστήματος. Εξαιτίας της εγγραφής και ανάγνωσης σε αυτήν από πολλαπλές διεργασίες, οι τελευταίες είναι ικανές να ανταλλάξουν δεδομένα.
oΈστω ότι σε κάποιο σημείο του κώδικά της (π.χ. στη γραμμή 158 του πηγαίου κώδικα) η διεργασία Α προβαίνει στην εξής ακολουθία εντολών – σε ψευδοκώδικα υψηλού επιπέδου:
158. Αν (c == 30) Τότε …(κάποια εντολή Χ);
159. Αλλιώς …(κάποια εντολή Υ);
oΠροφανώς το εν λόγω τμήμα κώδικα είναι κρίσιμο, αφού προσπελαύνεται (διαβάζεται) η κοινόχρηστη μεταβλητή c.
oΈστω τώρα ότι σε κάποιο σημείο του κώδικά της (π.χ. στη γραμμή 547 του πηγαίου κώδικα) η διεργασία Β περιέχει την εξής εντολή:
547. c = 10;
Πρόκειται πάλι για κρίσιμο κώδικα, όπου γράφεται η κοινόχρηστη μεταβλητή c.
- Παράδειγμα (Μέρος 2ο):
oΑν οι διεργασίες Α και Β τρέχουν ταυτόχρονα (παράλληλα ή ψευδοπαράλληλα) και η εκτέλεσή τους τύχει να φτάσει περίπου την ίδια χρονική στιγμή στα εν λόγω κρίσιμα σημεία τους, τότε εμφανίζονται συνθήκες συναγωνισμού. Οι δύο διεργασίες επιχειρούν να προσπελάσουν ταυτόχρονα έναν κοινό πόρο (τη μεταβλητή c).
oΈστω ότι η διεργασία Α εισέρχεται στον κρίσιμο κώδικά της και εκτελεί πλήρως την εντολή 158, έχοντας βρει ότι η τιμή της c είναι πράγματι 30. Αμέσως μετά ο χρονοπρογραμματιστής παγώνει την εκτέλεση της Α και δίνει τον έλεγχο στη Β, η οποία συνεχίζει την εκτέλεση του κώδικά της ώσπου εκτελεί την εντολή 547 (c = 10).
oΣε αυτήν την περίπτωση δεν υπάρχει πρόβλημα, παρόλο που εμφανίστηκαν συνθήκες συναγωνισμού. Ίσως βέβαια δημιουργείται λογικό σφάλμα και ο κώδικας θα έπρεπε να είναι δομημένος αλλιώς, αλλά αυτό δεν είναι σφάλμα συνέπειας εξαιτίας συνθηκών συναγωνισμού.
oΣκεφτείτε τώρα το εξής παραλλαγμένο σενάριο: ο χρονοπρογραμματιστής παγώνει την εκτέλεση της Α αμέσως μετά τη σύγκριση (όπου εξακριβώνεται ότι η c έχει τιμή 30) αλλά πριν από την εκτέλεση της εντολής X. Αμέσως μετά ο έλεγχος δίνεται στη διεργασία Β, η οποία κάποια στιγμή εκτελεί την εντολή 547 και αλλάζει την τιμή της c σε 10.
oΌταν κάποτε ο έλεγχος του επεξεργαστή επιστρέψει στην Α και αυτή συνεχίσει την εκτέλεσή της, θα τρέξει την εντολή Χ, γιατί η Α ακόμα νομίζει πως η c έχει τιμή 30, σύμφωνα με τη σύγκριση που προηγήθηκε. Στην πραγματικότητα όμως η c στον χρόνο που μεσολάβησε έχει αλλάξει τιμή, λόγω της θεματικής εναλλαγής, και η εντολή που θα έπρεπε να εκτελεστεί είναι η Υ. Εδώ έχουμε ένα σφάλμα συνέπειας το οποίο οδηγεί το εκτελούμενο πρόγραμμα σε κατάσταση λάθους.
oΤο πότε οι συνθήκες συναγωνισμού οδηγούν πράγματι σε σφάλμα συνέπειας κατά την εκτέλεση ενός προγράμματος, δεν μπορούμε να το γνωρίζουμε εκ των προτέρων καθώς – στο συγκεκριμένο παράδειγμα – τα πάντα εξαρτώνται από τις αποφάσεις του χρονοπρογραμματιστή.
oΕίναι δυνατόν ένα πρόγραμμα στο οποίο παρουσιάζονται συνθήκες συναγωνισμού να εκτελεστεί 100 διαφορετικές φορές και μόνο τις 3 – ή και ποτέ – να δημιουργηθεί πρόβλημα. Είναι εξίσου πιθανόν όμως να παρουσιαστεί πρόβλημα στις 80 από τις 100 εκτελέσεις. Ο προγραμματιστής πρέπει σε κάθε περίπτωση να έχει λάβει τα μέτρα του.
- Αμοιβαίος Αποκλεισμός (Mutual Exclusion):
oΤα λειτουργικά συστήματα παρέχουν ένα σύνολο μηχανισμών, συνήθως προσπελάσιμων από τους προγραμματιστές μέσω κλήσεων συστήματος, οι οποίοι απαγορεύουν σε δύο διεργασίες που διαμοιράζονται κάποιον κοινό πόρο να εισέρχονται ταυτόχρονα σε κρίσιμα σημεία του κώδικά τους.
oΣτόχος είναι η απάλειψη των συνθηκών συναγωνισμού μέσω κατάλληλου προγραμματισμού, ώστε να εξαλειφθούν κατά το δυνατόν τα προβλήματα συνέπειας. Οι μηχανισμοί αυτοί συνιστούν τον λεγόμενο αμοιβαίο αποκλεισμό.
oΥπάρχουν πολλές διαφορετικές πρακτικές αμοιβαίου αποκλεισμού, οι οποίες απαιτούν υποστήριξη και από το λειτουργικό σύστημα και από τη γλώσσα προγραμματισμού, ενώ ορισμένες απαιτούν κατάλληλη υποστήριξη και από τον επεξεργαστή (πρέπει ο τελευταίος να περιλαμβάνει κάποιες συγκεκριμένες εντολές χαμηλού επιπέδου στην αρχιτεκτονική του).
oΣτην πράξη η συνηθέστερη μέθοδος αμοιβαίου αποκλεισμού είναι τα λεγόμενα κλειδώματα ή κλειδαριές (locks), γνωστά και ως mutex. Ένα mutex είναι μία μεταβλητή ειδικού τύπου δεδομένων, παρεχόμενου από τις βιβλιοθήκες του λειτουργικού συστήματος, η οποία τοποθετείται από τον προγραμματιστή σε κοινή μνήμη.
oΣτην αρχή κάθε κρίσιμου σημείου κάθε διεργασίας, ο προγραμματιστής πρέπει να «κλειδώνει» το mutex μέσω μίας διαδικασίας που παρέχει η βιβλιοθήκη συστήματος. Από τη στιγμή που το mutex έχει κλειδωθεί, ακόμα και αν η διεργασία που το κλείδωσε (έστω η Α) παγώσει, κάθε άλλη διεργασία η οποία θα φτάσει επίσης σε κρίσιμο σημείο του κώδικά της και επιχειρήσει να το κλειδώσει για λογαριασμό της (έστω η Β), αυτομάτως θα ανασταλεί και θα παγώσει.
oΣτο τέλος κάθε κρίσιμου σημείου κάθε διεργασίας, ο προγραμματιστής πρέπει να «ξεκλειδώνει» το mutex μέσω μίας διαδικασίας που παρέχει η βιβλιοθήκη συστήματος. Αφού το mutex ξεκλειδωθεί, όταν ο χρονοπρογραμματιστής δώσει ξανά τον έλεγχο σε μια διεργασία η οποία έχει είναι σε αναστολή επειδή παλιότερα ζήτησε το κλείδωμα, η διεργασία αυτή θα μπορεί να συνεχίσει την εκτέλεσή της και να εισέλθει στο κρίσιμο σημείο της.
oΑυτό που επιτυγχάνουμε είναι ότι κάθε στιγμή, η εκτέλεση μόνο μίας διεργασίας μπορεί να βρίσκεται σε κρίσιμο κώδικα. Όλα φυσικά εξαρτώνται από τον προγραμματιστή, στο χέρι του οποίου είναι ο ορισμός και η ορθή αξιοποίηση των κατάλληλων mutex. Σημαντικό είναι ότι ένα τέτοιο κλείδωμα πρέπει πάντοτε να ξεκλειδώνεται στο τέλος μίας κρίσιμης περιοχής, διαφορετικά οι διεργασίες που έχουν ανασταλεί επειδή δοκίμασαν να το κλειδώσουν δεν θα καταφέρουν ποτέ να συνεχίσουν την εκτέλεσή τους!
oΠροφανώς, για κρίσιμες περιοχές ενός προγράμματος οι οποίες αφορούν διαφορετικούς κοινόχρηστους πόρους, δεν έχει νόημα η χρήση του ίδιου κλειδώματος: πρέπει να ορίζονται και να κλειδώνονται / ξεκλειδώνονται διαφορετικά mutex.
oΟ αμοιβαίος αποκλεισμός – αν και αναγκαίος για την επίλυση συνθηκών συναγωνισμού – ίσως μειώνει τις επιδόσεις ορισμένων προγραμμάτων, αφού σειριοποιεί την πρόσβασή τους σε κοινόχρηστους πόρους: η μία διεργασία πρέπει να περιμένει την άλλη να τελειώσει ένα τμήμα της εκτέλεσής της. Αυτό το ζήτημα ανακύπτει κυρίως σε παράλληλα πολυεπεξεργαστικά συστήματα, καθώς ένας ή περισσότεροι από τους επεξεργαστές μένουν αδρανείς για κάποιο χρόνο, λόγω αναμονής σε mutex των διεργασιών που εκτελούν. Όταν επομένως το ζητούμενο είναι οι υψηλές επιδόσεις, τα προγράμματα πρέπει να σχεδιάζονται έτσι ώστε να ελαχιστοποιείται η χρήση αμοιβαίου αποκλεισμού.
- Παράδειγμα (Μέρος 3ο):
- Στο προηγούμενο παράδειγμα με τις διεργασίες Α και Β, ο κώδικάς τους πρέπει να είναι ως εξής:
· Α:
158. Κλείδωσε (my_mutex);
159. Αν (c == 30) Τότε …(κάποια εντολή Χ);
160. Αλλιώς …(κάποια εντολή Υ);
161. Ξεκλείδωσε (my_mutex);
· Β:
547. Κλείδωσε (my_mutex);
548. c = 10;
549. Ξεκλείδωσε (my_mutex);- Συγχρονισμός (Synchronization):
oΔεν είναι ασυνήθιστο, κυρίως σε προγράμματα τα οποία αξιοποιούν ιεραρχίες συνεργαζόμενων διεργασιών, μία διεργασία να πρέπει να περιμένει μία ή περισσότερες άλλες προκειμένου να μπορέσει να συνεχίσει τη λειτουργία της, ώστε να διασφαλιστεί η ορθότητα του αποτελέσματος.
o Π.χ. έστω ότι σε ένα παράλληλο πολυεπεξεργαστικό σύστημα, έχει διαμοιραστεί σε πολλές διεργασίες ένας χρονοβόρος υπολογισμός και καθεμία εκτελεί ένα μέρος του. Προτού συνεχιστεί η εκτέλεση του κύριου προγράμματος όμως, είναι αναγκαίο ο πλήρης υπολογισμός να έχει ολοκληρωθεί. Έτσι η γονική διεργασία πρέπει να περιμένει να τελειώσουν όλες οι θυγατρικές με το τμήμα του υπολογισμού που τους αναλογεί ώστε να συγκεντρώσει τα αποτελέσματα, προτού συνεχίσει με την εκτέλεσή της.
o Αυτό είναι ένα παράδειγμα προβλήματος συγχρονισμού. Ο συγχρονισμός συνήθως επιτυγχάνεται με εξειδικευμένες δομές δεδομένων που παρέχουν οι βιβλιοθήκες του λειτουργικού συστήματος (παρομοίως με τα κλειδώματα), τα φράγματα (barriers). Ο προγραμματιστής πρέπει να έχει γράψει κώδικα ο οποίος, με μία κατάλληλη κλήση συστήματος επί ενός φράγματος (τοποθετημένου σε κοινή μνήμη), αναστέλλει τη λειτουργία της τρέχουσας διεργασίας μέχρι όλες οι άλλες διεργασίες που προσπελαύνουν το φράγμα επίσης να προβούν στην ίδια κλήση. Έτσι σηματοδοτείται πως έφθασαν πλέον σε κατάλληλο σημείο της εκτέλεσής τους (έχουν τελειώσει το τμήμα του υπολογισμού που τους αναλογεί, στο προαναφερθέν παράδειγμα). Τότε όλες οι διεργασίες οι οποίες βρίσκονται εν αναμονή στο εν λόγω φράγμα, γίνονται αυτομάτως έτοιμες για εκτέλεση.
oΠροφανώς ο κώδικας των διεργασιών πρέπει να είναι καταλλήλως και ορθά γραμμένος από τον προγραμματιστή, ενώ το λειτουργικό σύστημα πρέπει να παρέχει μία βιβλιοθήκη με σωστά υλοποιημένα φράγματα.
oΈστω ότι οι συγχρονιζόμενες διεργασίες είναι μόνο δύο, η Α και η Β. Ο κώδικάς τους πρέπει να μοιάζει περίπου ως εξής (σε ψευδοκώδικα):
o Π.χ. έστω ότι σε ένα παράλληλο πολυεπεξεργαστικό σύστημα, έχει διαμοιραστεί σε πολλές διεργασίες ένας χρονοβόρος υπολογισμός και καθεμία εκτελεί ένα μέρος του. Προτού συνεχιστεί η εκτέλεση του κύριου προγράμματος όμως, είναι αναγκαίο ο πλήρης υπολογισμός να έχει ολοκληρωθεί. Έτσι η γονική διεργασία πρέπει να περιμένει να τελειώσουν όλες οι θυγατρικές με το τμήμα του υπολογισμού που τους αναλογεί ώστε να συγκεντρώσει τα αποτελέσματα, προτού συνεχίσει με την εκτέλεσή της.
o Αυτό είναι ένα παράδειγμα προβλήματος συγχρονισμού. Ο συγχρονισμός συνήθως επιτυγχάνεται με εξειδικευμένες δομές δεδομένων που παρέχουν οι βιβλιοθήκες του λειτουργικού συστήματος (παρομοίως με τα κλειδώματα), τα φράγματα (barriers). Ο προγραμματιστής πρέπει να έχει γράψει κώδικα ο οποίος, με μία κατάλληλη κλήση συστήματος επί ενός φράγματος (τοποθετημένου σε κοινή μνήμη), αναστέλλει τη λειτουργία της τρέχουσας διεργασίας μέχρι όλες οι άλλες διεργασίες που προσπελαύνουν το φράγμα επίσης να προβούν στην ίδια κλήση. Έτσι σηματοδοτείται πως έφθασαν πλέον σε κατάλληλο σημείο της εκτέλεσής τους (έχουν τελειώσει το τμήμα του υπολογισμού που τους αναλογεί, στο προαναφερθέν παράδειγμα). Τότε όλες οι διεργασίες οι οποίες βρίσκονται εν αναμονή στο εν λόγω φράγμα, γίνονται αυτομάτως έτοιμες για εκτέλεση.
oΠροφανώς ο κώδικας των διεργασιών πρέπει να είναι καταλλήλως και ορθά γραμμένος από τον προγραμματιστή, ενώ το λειτουργικό σύστημα πρέπει να παρέχει μία βιβλιοθήκη με σωστά υλοποιημένα φράγματα.
oΈστω ότι οι συγχρονιζόμενες διεργασίες είναι μόνο δύο, η Α και η Β. Ο κώδικάς τους πρέπει να μοιάζει περίπου ως εξής (σε ψευδοκώδικα):
· Α:
158. {Υπολογισμός...}
159. {Υπολογισμός...}
160. Αναμονή (my_barrier, 2);
· Β:
101. {Υπολογισμός...}
102. {Υπολογισμός...}
103. Αναμονή (my_barrier, 2);
oΌταν η Α εκτελέσει την κλήση αναμονής στη γραμμή 160 του πηγαίου κώδικά της, η λειτουργία της αναστέλλεται αυτομάτως από το ΛΣ ώσπου μία ακόμα διεργασία να εκτελέσει κλήση αναμονής στο ίδιο φράγμα. Ο αριθμός 2 που μεταβιβάζεται στο συγκεκριμένο παράδειγμα ως δεύτερο όρισμα στην κλήση αναμονής, πληροφορεί το ΛΣ ότι πρέπει ακριβώς δύο διεργασίες να έχουν ανασταλλεί στο φράγμα my_barrier για να παύσει η αναστολή τους και να γίνουν ξανά έτοιμες προς εκτέλεση.
oΌταν η Β φτάνει στο σημείο εκτέλεσης του κώδικά της όπου καλείται η αναμονή στο φράγμα, η εσωτερική υλοποίηση της κλήσης αναμονής από το λειτουργικό σύστημα αντιλαμβάνεται πως δύο διεργασίες έχουν ήδη ζητήσει αναστολή, οπότε τόσο η Α όσο και η Β είναι πλέον έτοιμες να συνεχίσουν κανονικά τη ροή εκτέλεσής τους. Από εκεί κι έπειτα είναι θέμα του χρονοπρογραμματιστή το ποια θα λάβει τον έλεγχο του επεξεργαστή.
oΌταν η Β φτάνει στο σημείο εκτέλεσης του κώδικά της όπου καλείται η αναμονή στο φράγμα, η εσωτερική υλοποίηση της κλήσης αναμονής από το λειτουργικό σύστημα αντιλαμβάνεται πως δύο διεργασίες έχουν ήδη ζητήσει αναστολή, οπότε τόσο η Α όσο και η Β είναι πλέον έτοιμες να συνεχίσουν κανονικά τη ροή εκτέλεσής τους. Από εκεί κι έπειτα είναι θέμα του χρονοπρογραμματιστή το ποια θα λάβει τον έλεγχο του επεξεργαστή.
- Πρόβλημα παραγωγού - καταναλωτή:
oΤυπικό παράδειγμα όπου απαιτείται συγχρονισμός είναι το πρόβλημα παραγωγού - καταναλωτή: αν μία διεργασία παράγει διαρκώς δεδομένα και τα τοποθετεί σε μία κοινή μνήμη, ενώ μία δεύτερη διεργασία διαρκώς διαβάζει τα εν λόγω δεδομένα αφαιρώντας τα από τη μνήμη αυτή, δημιουργείται ζήτημα συγχρονισμού σε περίπτωση που οι δύο εμπλεκόμενες διεργασίες εκτελούνται με διαφορετικούς χρονικούς ρυθμούς.
oΑν ο παραγωγός γράφει περισσότερα δεδομένα στη μονάδα του χρόνου απ' όσα διαβάζει ο καταναλωτής, είναι πιθανόν η μνήμη κάποια στιγμή να γεμίσει και η προσπάθεια εγγραφής σε αυτή να αποτύχει. Αν ο καταναλωτής διαβάζει περισσότερα δεδομένα στη μονάδα του χρόνου απ' ότι γράφει ο παραγωγός, είναι πιθανόν η μνήμη κάποια στιγμή να αδειάσει και η προσπάθεια ανάγνωσης από αυτή να αποτύχει.
oΚαι στις δύο περιπτώσεις εμφανίζεται απώλεια δεδομένων, η οποία είναι δυνατόν να αντιμετωπιστεί με μεθόδους συγχρονισμού όπως τα φράγματα.
oΌταν τρέχουν δύο διεργασίες και η καθεμία αναμένει την άλλη να εκτελέσει μία λειτουργία (π.χ. να ξεκλειδώσει ένα κοινό τους mutex) ώστε να συνεχίσει η ίδια την εκτέλεσή της, τελικά καμία δεν προχωρά και μένουν αιωνίως εν αναμονή. Αυτό το φαινόμενο είναι αποτέλεσμα εσφαλμένου ή απρόσεκτου σχεδιασμού και λέγεται αδιέξοδο.
o Τα αδιέξοδα εμφανίζονται σε περιπτώσεις κοινοχρησίας πόρων από πολλαπλές διεργασίες, όταν η καθεμία δεσμεύει έναν πόρο (π.χ. κλειδώνει ένα mutex) τον οποίον τυγχάνει να απαιτεί και η άλλη για να μπορεί να συνεχίσει. Έτσι η διεργασία Α δεν μπορεί να προχωρήσει με την εκτέλεσή της αν η Β δεν απελευθερώσει έναν κοινό πόρο, αλλά και η Β δεν μπορεί να προχωρήσει αν πρώτα η Α δεν κάνει το ίδιο με έναν άλλο πόρο. Υπάρχει επομένως μία σχέση κυκλικής εξάρτησης και καμία διεργασία δεν είναι σε θέση να συνεχίσει την εκτέλεσή της, ώστε να απελευθερώσει τον πόρο που κατέχει.
oΕίναι δύσκολο έως αδύνατο να προβλεφθεί η εμφάνιση ενός αδιεξόδου κατά τον χρόνο εκτέλεσης του λογισμικού. Μόνη αξιόπιστη λύση είναι ο προσεκτικός σχεδιασμός και προγραμματισμός του κώδικα, κυρίως όταν χρησιμοποιείται συγχρονισμός ή αμοιβαίος αποκλεισμός.
oΣε ορισμένες περιπτώσεις, με κατάλληλο σχεδιασμό, ειδικές δομές δεδομένων και υποστήριξη από το υλικό, είναι εφικτή η αξιοποίηση αλγορίθμων οι οποίοι αποφεύγουν τη χρήση αμοιβαίου αποκλεισμού, χωρίς να δημιουργούνται προβλήματα συνέπειας (μη ανασταλτικοί αλγόριθμοι). Έτσι εξαλείφεται η πιθανότητα εμφάνισης αδιεξόδου κατά τον χρόνο εκτέλεσης του λογισμικού, ενώ επίσης αυξάνεται ο παραλληλισμός σε πολυεπεξεργαστικά συστήματα, αφού ο κώδικας δεν σειριοποιείται ποτέ λόγω αμοιβαίου αποκλεισμού.
oΑν ο παραγωγός γράφει περισσότερα δεδομένα στη μονάδα του χρόνου απ' όσα διαβάζει ο καταναλωτής, είναι πιθανόν η μνήμη κάποια στιγμή να γεμίσει και η προσπάθεια εγγραφής σε αυτή να αποτύχει. Αν ο καταναλωτής διαβάζει περισσότερα δεδομένα στη μονάδα του χρόνου απ' ότι γράφει ο παραγωγός, είναι πιθανόν η μνήμη κάποια στιγμή να αδειάσει και η προσπάθεια ανάγνωσης από αυτή να αποτύχει.
oΚαι στις δύο περιπτώσεις εμφανίζεται απώλεια δεδομένων, η οποία είναι δυνατόν να αντιμετωπιστεί με μεθόδους συγχρονισμού όπως τα φράγματα.
- Αδιέξοδα (Deadlock):
o Τα αδιέξοδα εμφανίζονται σε περιπτώσεις κοινοχρησίας πόρων από πολλαπλές διεργασίες, όταν η καθεμία δεσμεύει έναν πόρο (π.χ. κλειδώνει ένα mutex) τον οποίον τυγχάνει να απαιτεί και η άλλη για να μπορεί να συνεχίσει. Έτσι η διεργασία Α δεν μπορεί να προχωρήσει με την εκτέλεσή της αν η Β δεν απελευθερώσει έναν κοινό πόρο, αλλά και η Β δεν μπορεί να προχωρήσει αν πρώτα η Α δεν κάνει το ίδιο με έναν άλλο πόρο. Υπάρχει επομένως μία σχέση κυκλικής εξάρτησης και καμία διεργασία δεν είναι σε θέση να συνεχίσει την εκτέλεσή της, ώστε να απελευθερώσει τον πόρο που κατέχει.
oΕίναι δύσκολο έως αδύνατο να προβλεφθεί η εμφάνιση ενός αδιεξόδου κατά τον χρόνο εκτέλεσης του λογισμικού. Μόνη αξιόπιστη λύση είναι ο προσεκτικός σχεδιασμός και προγραμματισμός του κώδικα, κυρίως όταν χρησιμοποιείται συγχρονισμός ή αμοιβαίος αποκλεισμός.
oΣε ορισμένες περιπτώσεις, με κατάλληλο σχεδιασμό, ειδικές δομές δεδομένων και υποστήριξη από το υλικό, είναι εφικτή η αξιοποίηση αλγορίθμων οι οποίοι αποφεύγουν τη χρήση αμοιβαίου αποκλεισμού, χωρίς να δημιουργούνται προβλήματα συνέπειας (μη ανασταλτικοί αλγόριθμοι). Έτσι εξαλείφεται η πιθανότητα εμφάνισης αδιεξόδου κατά τον χρόνο εκτέλεσης του λογισμικού, ενώ επίσης αυξάνεται ο παραλληλισμός σε πολυεπεξεργαστικά συστήματα, αφού ο κώδικας δεν σειριοποιείται ποτέ λόγω αμοιβαίου αποκλεισμού.
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου
Αφήστε το σχόλιό σας για την τρέχουσα ανάρτηση: