Διδακτικά Βιβλία του Παιδαγωγικού Ινστιτούτου

Αναζήτηση

Βρες
Εμφάνιση

Το πρόβλημα των αναγνωστών και συγγραφέων

Στις βάσεις δεδομένων (databases) παρουσιάζεται ένα πολύ συνηθισμένο πρόβλημα αμοιβαίου αποκλεισμού διεργασιών, το πρόβλημα των αναγνωστών και συγγραφέων. Μια ομάδα διεργασιών μοιράζεται ένα αρχείο, στο οποίο άλλες διεργασίες θέλουν να γράψουν και να το τροποποιήσουν, ενώ άλλες θέλουν μόνο να διαβάσουν από αυτό. Για να εξασφαλίζεται το ότι τα περιεχόμενα του αρχείου είναι σωστά, πρέπει οι συγγραφείς να έχουν αποκλειστική πρόσβαση στο αρχείο. Όταν γράφει λοιπόν μια διεργασία-συγγραφέας καμία άλλη διεργασία δεν έχει πρόσβαση στο αρχείο. Αντίθετα, πολλές διεργασίες-αναγνώστες μπορούν να διαβάζουν ταυτόχρονα.

Για να δώσουμε μια λύση στο πρόβλημα αυτό πρέπει να αποφασίσουμε ποιοι θα έχουν προτεραιότητα: οι αναγνώστες ή οι συγγραφείς, όταν ταυτόχρονα μια διεργασία θέλει να διαβάσει και μια θέλει να γράψει. Εμείς θα υποθέσουμε εδώ ότι προηγούνται οι αναγνώστες, δηλαδή οι συγγραφείς περιμένουν να ολοκληρωθούν οι λειτουργίες ανάγνωσης.

- Στη συνέχεια πρέπει να αποφασίσουμε ποιους σηματοφορείς και μεταβλητές θα χρησιμοποιήσουμε και ποιο ρόλο θα αναλάβει ο καθένας. Θα εξετάζουμε ένα-ένα τα προβλήματα ακεραιότητας δεδομένων που υπάρχουν και θα προσθέτουμε διαδοχικά εντολές στον κώδικα των διεργασιών. Οι απλούστερες μορφές του κώδικα φαίνονται στο σχήμα. Η διεργασία - συγγραφέας γράφει στο αρχείο myfile, ενώ η διεργασία - αναγνώστης διαβάζει από αυτό.

- Οπωσδήποτε πρέπει να χρησιμοποιήσουμε ένα σηματοφορέα ο οποίος θα εξασφαλίζει το ότι μόνο ένας συγγραφέας θα γράφει ανά πάσα στιγμή στο αρχείο, ώστε οι αλλαγές στο αρχείο να γίνονται σωστά. Κάθε συγγραφέας προτού γράψει θα καταλαμβάνει το σηματοφορέα αυτό και όταν τελειώνει θα τον ελευθερώνει. Το όνομα του σηματοφορέα θα είναι write_sema.

Τώρα κάθε διεργασία - συγγραφέας εκτελεί μία λειτουργία Ρ στο σηματοφορέα, και όταν αυτή ολοκληρωθεί εκτελεί την εγγραφή. Στη συνέχεια απελευθερώνει το σηματοφορέα με τη λειτουργία V για να τον διαθέσει στους υπόλοιπους συγγραφείς.

- Για να βεβαιωθούν οι αναγνώστες ότι δε γράφει κάποιος στο αρχείο πριν διαβάσουν, πρέπει πριν από την ανάγνωση να καταλάβουν το σηματοφορέα write_sema. Όμως, όταν ένας αναγνώστης έχει καταλάβει το σηματοφορέα με τη λειτουργία Ρ, όλοι οι άλλοι που θα εκτελέσουν επίσης την Ρ θα τον περιμένουν. Αυτό είναι κάτι ανεπιθύμητο, μια που πολλοί αναγνώστες μπορούν να διαβάζουν ταυτόχρονα. Έτσι, αρκεί ο πρώτος αναγνώστης να καταλάβει το σηματοφορέα αυτό, και οι υπόλοιποι μπορούν πλέον να διαβάζουν άφοβα. Ο τελευταίος αναγνώστης αντίστοιχα πρέπει να ελευθερώσει τον write_sema.

Για να διαπιστώσει μια διεργασία - αναγνώστης αν είναι η πρώτη, πρέπει σε μια μεταβλητή να κρατείται το πλήθος των αναγνωστών που είναι ενεργοί ανά πάσα στιγμή· στην μεταβλητή θα δώσουμε το όνομα readcount. Αρχικά η μεταβλητή έχει την τιμή 0, κάθε αναγνώστης την αυξάνει πριν από την ανάγνωση, και τη μειώνει μετά από αυτήν. Ο πρώτος αναγνώστης, αφού αυξήσει τη readcount, θα διαπιστώσει ότι έχει την τιμή 1 και θα καταλάβει το σηματοφορέα write_sema. Ο τελευταίος, όταν τη μειώσει, θα διαπιστώσει ότι έχει πάλι τιμή 0 και θα ελευθερώσει το σηματοφορέα write_sema.

- Όμως η προσθήκη που κάναμε στους αναγνώστες έχει ένα πρόβλημα: μπορεί πολλοί αναγνώστες μαζί να αυξάνουν ή να μειώνουν τη μεταβλητή readcount, και μετά να ελέγχουν την τιμή της. Σε μια τέτοια περίπτωση τα αποτελέσματα είναι ανεξέλεγκτα και συνήθως όχι σωστά. Μια που η readcount είναι μοιραζόμενη μεταβλητή, η πρόσβαση σε αυτήν πρέπει να φυλάσσεται από ένα σηματοφορέα, στον οποίο θα δώσουμε το όνομα rc_sema. Οι αναγνώστες θα καταλαμβάνουν τον rc_sema πριν να αυξήσουν την τιμή της readcount και θα τον ελευθερώνουν αφού έχουν ελέγξει την τιμή της.