The University of Adelaide, School of Computer Science Εισαγωγή στον παράλληλο προγραμματισμό Peter Pacheco The University of Adelaide, School of Computer Science 23 October 2017 Κεφάλαιο 4 Προγραμματισμός συστημάτων κοινόχρηστης μνήμης με Pthreads Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved. Chapter 2 — Instructions: Language of the Computer
The University of Adelaide, School of Computer Science 23 October 2017 Περίγραμμα κεφαλαίου Προβλήματα στον προγραμματισμό συστημάτων κοινόχρηστης μνήμης. Έλεγχος της πρόσβασης σε κρίσιμα τμήματα. Συγχρονισμός νημάτων. Προγραμματισμός με νήματα POSIX. Mutex. Συγχρονισμός παραγωγού-καταναλωτή και σηματοφορείς. Φράγματα και μεταβλητές συνθήκης. Κλειδώματα ανάγνωσης-εγγραφής. Ασφάλεια νημάτωσης. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved. Chapter 2 — Instructions: Language of the Computer
Σύστημα κοινόχρηστης μνήμης Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Διεργασίες και νήματα Διεργασία (process) είναι ένα στιγμιότυπο ενός προγράμματος που είτε εκτελείται είτε βρίσκεται σε κατάσταση «αναστολής». Τα νήματα (threads) είναι ένα είδος «ελαφρών» εργασιών. Στα προγράμματα κοινόχρηστης μνήμης μία διεργασία μπορεί να διαθέτει πολλά νήματα ελέγχου. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Νήματα POSIX® Γνωστά ως Pthreads. Το POSIX είναι ένα πρότυπο των λειτουργικών συστημάτων που βασίζονται στο Unix. Μια βιβλιοθήκη που μπορεί να συνδέεται σε προγράμματα C. Καθορίζει μια διασύνδεση προγραμματισμού εφαρμογών (API) για τον πολυνηματικό προγραμματισμό. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Περιορισμός Η διασύνδεση προγραμματισμού Pthreads είναι διαθέσιμη μόνο για συστήματα POSIX – όπως τα Linux, Mac OS X, Solaris, HPUX, κ.λπ. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Hello World! (1) Περιλαμβάνει τις δηλώσεις διαφόρων συναρτήσεων, σταθερών, τύπων, κ.λπ. της Pthreads. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Hello World! (2) Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Hello World! (3) Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Μεταγλώττιση προγράμματος Pthreads gcc −g −Wall −o pth_hello pth_hello . c −lpthread σύνδεση με τη βιβλιοθήκη Pthreads Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Εκτέλεση προγράμματος Pthreads . / pth_hello <πλήθος νημάτων> . / pth_hello 1 Χαιρετισμούς από το κύριο νήμα Χαιρετισμούς από το νήμα 0 από 1 . / pth_hello 4 Χαιρετισμούς από το κύριο νήμα Χαιρετισμούς από το νήμα 0 από 4 Χαιρετισμούς από το νήμα 1 από 4 Χαιρετισμούς από το νήμα 2 από 4 Χαιρετισμούς από το νήμα 3 από 4 Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Καθολικές μεταβλητές Μπορούν να προκαλέσουν δυσδιάκριτα και περίπλοκα σφάλματα στον κώδικα! Να περιορίζετε τη χρήση καθολικών μεταβλητών μόνο στις περιπτώσεις όπου είναι πραγματικά απαραίτητες. Κοινόχρηστες (shared) μεταβλητές. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Εκκίνηση των νημάτων Οι διεργασίες στην MPI ξεκινούν συνήθως μέσω ενός σεναρίου ενεργειών. Στην Pthreads, τα νήματα ξεκινούν από το εκτελέσιμο αρχείο του προγράμματος. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
The University of Adelaide, School of Computer Science 23 October 2017 Εκκίνηση των νημάτων pthread.h Ένα αντικείμενο για κάθε νήμα. pthread_t int pthread_create ( pthread_t* thread_p /* έξοδος */ , const pthread_attr_t* attr_p /* είσοδος */ , void* (*start_routine ) ( void ) /* είσοδος */ , void* arg_p /* είσοδος*/ ) ; Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved. Chapter 2 — Instructions: Language of the Computer
Αντικείμενα pthread_t Αδιαφανή Τα πραγματικά δεδομένα τους εξαρτώνται από το σύστημα. Τα μέλη δεδομένων τους δεν είναι άμεσα προσπελάσιμα από τον κώδικα χρήστη. Ωστόσο, το πρότυπο Pthreads εγγυάται ότι ένα αντικείμενο pthread_t περιλαμβάνει αρκετές πληροφορίες ώστε να αναγνωρίζεται με μοναδικό τρόπο το νήμα με το οποίο είναι συσχετισμένο το αντικείμενο. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Μια πιο κοντινή ματιά (1) int pthread_create ( pthread_t* thread_p /* έξοδος */ , const pthread_attr_t* attr_p /* είσοδος */ , void* (*start_routine ) ( void ) /* είσοδος */ , void* arg_p /* είσοδος */ ) ; Δεν θα το χρησιμοποιούμε, γι’ αυτό θα μεταβιβάζουμε στη θέση του την τιμή NULL. Δέσμευση μνήμης πριν την κλήση. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Μια πιο κοντινή ματιά (2) int pthread_create ( pthread_t* thread_p /* έξοδος */ , const pthread_attr_t* attr_p /* είσοδος */ , void* (*start_routine ) ( void ) /* είσοδος*/ , void* arg_p /* είσοδος*/ ) ; Δείκτης προς το όρισμα που πρέπει να μεταβιβαστεί στη συνάρτηση start_routine. Η συνάρτηση που θα εκτελείται από το νήμα. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Η συνάρτηση που εκτελείται από την pthread_create Πρωτότυπο: void* συνάρτηση_νήματος ( void* args_p ) ; Ο τύπος void* μπορεί να μετατραπεί σε οποιονδήποτε τύπο δείκτη στη C. Επομένως το όρισμα args_p μπορεί να δείχνει σε μια λίστα που να περιλαμβάνει τις όποιες τιμές χρειάζεται η συνάρτηση_νήματος. Παρόμοια, η επιστρεφόμενη τιμή της συνάρτηση_νήματος μπορεί να δείχνει σε κάποια λίστα με μία ή περισσότερες τιμές. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Εκτέλεση των νημάτων Κύριο νήμα που διακλαδίζεται σε δύο νήματα τα οποία επανενώνονται τελικά με το κύριο Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Τερματισμός των νημάτων Καλούμε τη συνάρτηση pthread_join μία φορά για κάθε νήμα. Μία κλήση της pthread_join θα περιμένει μέχρι να ολοκληρωθεί το νήμα που είναι συσχετισμένο με το αντικείμενο pthread_t. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
ΠΟΛΛΑΠΛΑΣΙΑΣΜΟΣ ΜΗΤΡΑΣ ΜΕ ΔΙΑΝΥΣΜΑ ΣΤΗΝ PTHREADS Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Σειριακός ψευδοκώδικας Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Χρήση 3 νημάτων νήμα 0 γενική περίπτωση Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Πολλ/μός μήτρας-διανύσματος Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
ΚΡΙΣΙΜΑ ΤΜΗΜΑΤΑ Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Αριθμητική προσέγγιση του π Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Χρήση διπύρηνου επεξεργαστή Παρατηρήστε ότι καθώς αυξάνουμε το n, η προσέγγιση της τιμής του π με ένα νήμα όλο και βελτιώνεται Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συνάρ/ση νήματος για υπολ/μό του π Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Πιθανή συνθήκη ανταγωνισμού Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Αναμονή σε εγρήγορση Ένα νήμα ελέγχει επανειλημμένα μια συνθήκη χωρίς ουσιαστικά να κάνει κάποια χρήσιμη εργασία μέχρι η συνθήκη να αποκτήσει την κατάλληλη τιμή. Προσοχή όμως στους μεταγλωττιστές βελτιστοποίησης! η μεταβλητή-σημαία (flag) έχει πάρει την τιμή 0 από το κύριο νήμα Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Καθολική άθροιση με αναμονή σε εγρήγορση Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συνάρτηση καθολικής άθροισης με το κρίσιμο τμήμα τοποθετημένο μετά τον βρόχο (1) Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συνάρτηση καθολικής άθροισης με το κρίσιμο τμήμα τοποθετημένο μετά τον βρόχο (2) Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Κλειδώματα αμοιβαίου αποκλεισμού (mutex) Ένα νήμα σε κατάσταση αναμονής σε εγρήγορση μπορεί να χρησιμοποιεί συνεχώς τη CPU χωρίς να κάνει απολύτως τίποτα. Τα mutex (mutual exclusion, αμοιβαίος αποκλεισμός) είναι μεταβλητές ειδικού τύπου, οι οποίες, σε συνδυασμό με αντίστοιχες συναρτήσεις, επιτρέπουν την προσπέλαση ενός κρίσιμου τμήματος από ένα μόνο νήμα κάθε φορά. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Mutex Διασφαλίζουν ότι ένα νήμα θα «αποκλείει» όλα τα υπόλοιπα όσο το συγκεκριμένο νήμα εκτελεί το κρίσιμο τμήμα. Το πρότυπο Pthreads περιλαμβάνει έναν ειδικό τύπο για τα mutex, τον pthread_mutex_t. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Mutex Όταν ένα πρόγραμμα Pthreads έχει τελειώσει με τη χρήση ενός mutex, θα πρέπει να καλεί την Για να προσπελάσει κάποιο κρίσιμο τμήμα, ένα νήμα πρέπει να καλέσει την Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Mutex Όταν ένα νήμα τελειώνει με την εκτέλεση του κώδικα κάποιου κρίσιμου τμήματος, θα πρέπει να εκτελεί την κλήση Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συνάρτηση καθολικής άθροισης με mutex (1) Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συνάρτηση καθολικής άθροισης με mutex (2) Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Χρόνοι εκτέλεσης (δευτερόλεπτα) των προγραμμάτων υπολογισμού του π, όταν χρησιμοποιούνται n = 108 όροι σε ένα σύστημα με δύο τετραπύρηνους επεξεργαστές. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Πιθανή ακολουθία συμβάντων με αναμονή σε εγρήγορση και περισσότερα νήματα από πυρήνες. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
ΣΥΓΧΡΟΝΙΣΜΟΣ ΠΑΡΑΓΩΓΟΥ-ΚΑΤΑΝΑΛΩΤΗ ΚΑΙ ΣΗΜΑΤΟΦΟΡΕΙΣ ΣΥΓΧΡΟΝΙΣΜΟΣ ΠΑΡΑΓΩΓΟΥ-ΚΑΤΑΝΑΛΩΤΗ ΚΑΙ ΣΗΜΑΤΟΦΟΡΕΙΣ Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Ζητήματα Η αναμονή σε εγρήγορση αναγκάζει τα νήματα να προσπελάζουν τα κρίσιμα τμήματα με συγκεκριμένη σειρά. Με τα mutex, η σειρά με την οποία τα νήματα εκτελούν το κρίσιμο τμήμα εξαρτάται από την τύχη και το σύστημα. Υπάρχουν εφαρμογές όπου χρειάζεται να ελέγχουμε τη σειρά με την οποία τα νήματα προσπελάζουν το κρίσιμο τμήμα. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Προβλήματα με τη χρήση mutex Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Μια πρώτη απόπειρα στην αποστολή μηνυμάτων με την Pthreads Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Σύνταξη συναρτήσεων σηματοφορέων Οι σηματοφορείς δεν αποτελούν τμήμα της Pthreads· πρέπει να συμπεριλάβετε το αντίστοιχο αρχείο κεφαλίδων. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
ΦΡΑΓΜΑΤΑ ΚΑΙ ΜΕΤΑΒΛΗΤΕΣ ΣΥΝΘΗΚΗΣ Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Φράγματα Ο συγχρονισμός των νημάτων ώστε να βρίσκονται όλα στο ίδιο σημείο εκτέλεσης του προγράμματος ονομάζεται φράγμα (barrier). Κανένα νήμα δεν επιτρέπεται να προχωρήσει πέρα από το φράγμα μέχρι να φτάσουν σε αυτό όλα τα νήματα. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Χρήση φραγμάτων για τη χρονομέτρηση του βραδύτερου νήματος Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Χρήση φραγμάτων για αποσφαλμάτωση Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Αναμονή σε εγρήγορση και mutex Όταν ο μετρητής αποκτήσει την τιμή που δείχνει ότι κάθε νήμα έχει φτάσει στο κρίσιμο τμήμα, τα νήματα μπορούν να εξέλθουν από τον βρόχο αναμονής σε εγρήγορση. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Αναμονή σε εγρήγορση και mutex Χρειαζόμαστε μια διαφορετική μεταβλητή-μετρητή για κάθε στιγμιότυπο του φράγματος, διαφορετικά θα προκύψουν προβλήματα. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Υλοποίηση φράγματος με σηματοφορείς Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Μεταβλητές συνθήκης Μια μεταβλητή συνθήκης είναι ένα αντικείμενο δεδομένων που επιτρέπει σε ένα νήμα να αναστέλλει την εκτέλεσή του μέχρι να προκύψει ένα συγκεκριμένο συμβάν, να ικανοποιηθεί δηλαδή μια συνθήκη. Όταν ικανοποιηθεί η συνθήκη, ένα άλλο νήμα μπορεί να στείλει το κατάλληλο σήμα στο νήμα για να «αφυπνιστεί». Μια μεταβλητή συνθήκης είναι πάντα συσχετισμένη με ένα mutex. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Μεταβλητές συνθήκης κλείδωμα mutex; if η συνθήκη ικανοποιήθηκε στείλε σήμα στο νήμα ή στα νήματα; else { ξεκλείδωμα mutex και μπλοκάρισμα νήματος; /* όταν το νήμα δεν είναι μπλοκαρισμένο, */ /* το mutex κλειδώνεται ξανά */ } ξεκλείδωμα mutex; Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Υλοποίηση φράγματος με μεταβλητές συνθήκης Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
ΚΛΕΙΔΩΜΑΤΑ ΑΝΑΓΝΩΣΗΣ-ΕΓΓΡΑΦΗΣ ΚΛΕΙΔΩΜΑΤΑ ΑΝΑΓΝΩΣΗΣ-ΕΓΓΡΑΦΗΣ Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Έλεγχος της πρόσβασης σε μεγάλη κοινόχρηστη δομή δεδομένων Ας δούμε ένα παράδειγμα. Ας υποθέσουμε ότι η κοινόχρηστη δομή δεδομένων είναι μια ταξινομημένη συνδεδεμένη λίστα ακεραίων, και ότι οι λειτουργίες που μας ενδιαφέρουν είναι οι Member (μέλος), Insert (εισαγωγή), και Delete (διαγραφή). Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συνδεδεμένες λίστες Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Έλεγχος ιδιότητας μέλους συνδεδεμένης λίστας Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Εισαγωγή νέου κόμβου σε λίστα Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Εισαγωγή νέου κόμβου σε λίστα Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Διαγραφή κόμβου από συνδεδεμένη λίστα Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Διαγραφή κόμβου από συνδεδεμένη λίστα Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Πολυνηματική συνδεδεμένη λίστα Ας δοκιμάσουμε τώρα να χρησιμοποιήσουμε αυτές τις συναρτήσεις σε ένα πρόγραμμα Pthreads. Για να επιτρέπεται η προσπέλαση της λίστας από όλα τα νήματα, μπορούμε να ορίσουμε τη head_p ως καθολική μεταβλητή. Έτσι απλοποιούνται οι κεφαλίδες των συναρτήσεων Member, Insert, και Delete, αφού δεν χρειάζεται πλέον να τους μεταβιβάζουμε τον head_p ή έναν δείκτη προς τον head_p, αλλά μόνο την τιμή που μας ενδιαφέρει. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Ταυτόχρονη προσπέλαση λίστας από δύο νήματα Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Λύση #1 Μια προφανής λύση είναι να κλειδώνουμε τη λίστα όποτε κάποιο νήμα επιχειρεί να την προσπελάσει. Μπορούμε να προστατεύουμε τις κλήσεις των τριών συναρτήσεων με ένα mutex: αντί, π.χ., της απλής κλήσης Member(value). Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Προβλήματα Έτσι επιτρέπουμε μόνο τη σειριακή προσπέλαση της λίστας. Αν η πλειονότητα των λειτουργιών στον κώδικά μας είναι κλήσεις της Member, ουσιαστικά δεν εκμεταλλευόμαστε την ευκαιρία που μας παρέχει αυτή η συνάρτηση για τη χρήση παραλληλίας. Αν όμως είναι περισσότερες οι κλήσεις των Insert και Delete, τότε ίσως αυτή να είναι η καλύτερη λύση, αφού θα πρέπει έτσι κι αλλιώς να σειριοποιήσουμε την προσπέλαση της λίστας για την πλειονότητα των λειτουργιών, και η υλοποίησή μιας τέτοιας λύσης είναι πανεύκολη. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Λύση #2 Αντί να κλειδώνουμε ολόκληρη τη λίστα, θα μπορούσαμε να δοκιμάσουμε το κλείδωμα μεμονωμένων κόμβων. Μια πιο «λεπτομερής» προσέγγιση: Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Προβλήματα Αυτή η λύση είναι πολύ πιο περίπλοκη από την αρχική συνάρτηση Member. Είναι επίσης πιο αργή, αφού κάθε φορά που προσπελάζεται ένας κόμβος πρέπει να κλειδώνεται και να ξεκλειδώνεται ένα mutex. Η προσθήκη ενός mutex σε κάθε κόμβο αυξάνει σημαντικά τον αποθηκευτικό χώρο που απαιτείται για τη λίστα. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Υλοποίηση της Member με ένα mutex για κάθε κόμβο (1) Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Υλοποίηση της Member με ένα mutex για κάθε κόμβο (2) Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Κλειδώματα ανάγνωσης-εγγραφής στην Pthreads Καμιά από τις δύο πολυνηματικές συνδεδεμένες λίστες που περιγράψαμε δεν εκμεταλλεύεται τη δυνατότητα ταυτόχρονης πρόσβασης σε οποιονδήποτε κόμβο από νήματα που εκτελούν τη Member. Η πρώτη λύση επιτρέπει την προσπέλαση της λίστας σε ένα μόνο νήμα κάθε φορά. Η δεύτερη επιτρέπει την προσπέλαση κάθε κόμβου μόνο από ένα νήμα σε κάθε δεδομένη χρονική στιγμή. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Κλειδώματα ανάγνωσης-εγγραφής στην Pthreads Ένα κλείδωμα ανάγνωσης-εγγραφής είναι κάτι σαν mutex, με τη διαφορά ότι παρέχει δύο συναρτήσεις κλειδώματος. Η πρώτη συνάρτηση κλειδώνει το κλείδωμα ανάγνωσης-εγγραφής μόνο για ανάγνωση, ενώ η δεύτερη το κλειδώνει για εγγραφή. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Κλειδώματα ανάγνωσης-εγγραφής στην Pthreads Επιτρέπεται έτσι σε πολλά νήματα ταυτόχρονα να προσλάβουν το κλείδωμα καλώντας τη συνάρτηση κλειδώματος για ανάγνωση, ενώ μόνο ένα νήμα επιτρέπεται να το προσλάβει καλώντας τη συνάρτηση κλειδώματος εγγραφής. Επομένως, αν κάποια νήματα έχουν προσλάβει το κλείδωμα ανάγνωσης, όποια νήματα χρειαστούν το κλείδωμα εγγραφής θα μπλοκαριστούν στην κλήση τους προς τη συνάρτηση κλειδώματος εγγραφής. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Κλειδώματα ανάγνωσης-εγγραφής στην Pthreads Αν οποιοδήποτε νήμα έχει προσλάβει το κλείδωμα εγγραφής, όποια άλλα νήματα θελήσουν να προσλάβουν το κλείδωμα ανάγνωσης ή το κλείδωμα εγγραφής θα μπλοκαριστούν στις κλήσεις τους προς τις αντίστοιχες συναρτήσεις κλειδώματος. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Προστασία των συναρτήσεων συνδεδεμένης λίστας Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Απόδοση συνδεδεμένης λίστας 100.000 λειτουργίες/νήμα 99,9% Member 0,05% Insert 0,05% Delete Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Απόδοση συνδεδεμένης λίστας 100.000 λειτουργίες/νήμα 80% Member 10% Insert 10% Delete Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Κρυφές μνήμες, συνοχή κρυφής μνήμης, και ψευδής κοινοχρησία Οι σχεδιαστές ολοκληρωμένων κυκλωμάτων έχουν ενσωματώσει στους επεξεργαστές μπλοκ ταχύτερης κρυφής μνήμης. Η χρήση κρυφής μνήμης μπορεί να έχει σημαντικό αντίκτυπο στα προγράμματα κοινόχρηστης μνήμης. Αστοχία εγγραφής έχουμε όταν ένας πυρήνας προσπαθεί να ενημερώσει μια μεταβλητή η οποία δεν βρίσκεται στην κρυφή μνήμη, οπότε αναγκάζεται να προσπελάσει την κύρια μνήμη. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Πολλαπλασιασμός μήτρας-διανύσματος με Pthreads Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Χρόνοι εκτέλεσης και αποδοτικότητες πολλ/μού μήτρας-διανύσματος (χρόνοι σε δευτερόλεπτα) Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
ΑΣΦΑΛΕΙΑ ΝΗΜΑΤΩΣΗΣ Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Ασφάλεια νημάτωσης Ένα μπλοκ κώδικα είναι ασφαλές για νημάτωση αν μπορεί να εκτελείται ταυτόχρονα από πολλά νήματα χωρίς να προκαλεί προβλήματα. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Παράδειγμα Υποθέστε ότι θέλουμε να διαιρέσουμε ένα αρχείο σε λεκτικές μονάδες (tokenization) χρησιμοποιώντας πολλά νήματα. Οι λεκτικές μονάδες (tokens) είναι απλώς ακολουθίες χαρακτήρων, διαχωρισμένες από το υπόλοιπο κείμενο με χαρακτήρες λευκού διαστήματος (κενό διάστημα, στηλοθέτης, ή αλλαγή γραμμής). Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Απλή προσέγγιση Χωρίζουμε το αρχείο εισόδου σε γραμμές κειμένου και αναθέτουμε αυτές τις γραμμές σε νήματα εκ περιτροπής. Η πρώτη γραμμή αποδίδεται στο νήμα 0, η δεύτερη στο νήμα 1, …, η t στη σειρά γραμμή αποδίδεται στο νήμα t – 1, η t + 1 αποδίδεται στο νήμα 0, κ.ο.κ. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Απλή προσέγγιση Μπορούμε να διασφαλίσουμε τη σειριακή πρόσβαση στις γραμμές εισόδου χρησιμοποιώντας σηματοφορείς. Αφού ένα νήμα διαβάσει μία γραμμή εισόδου, μπορεί να τη χωρίσει σε λεκτικές μονάδες (λέξεις) χρησιμοποιώντας τη συνάρτηση strtok. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Η συνάρτηση strtok Την πρώτη φορά που καλείται η strtok, το όρισμα string πρέπει να είναι η συμβολοσειρά που πρόκειται να διαιρεθεί σε λεκτικές μονάδες. Αυτή είναι η γραμμή εισόδου μας. Στις επόμενες κλήσεις της, το πρώτο όρισμα πρέπει να είναι NULL. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Η συνάρτηση strtok Η ιδέα είναι ότι, στην πρώτη κλήση, η strtok αποθηκεύει έναν δείκτη προς το όρισμα string και στις επόμενες κλήσεις επιστρέφει τις διαδοχικές λεκτικές μονάδες του αποθηκευμένου αντιγράφου. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Πολυνηματική συνάρτηση διάκρισης λεκτικών μονάδων (1) Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Πολυνηματική συνάρτηση διάκρισης λεκτικών μονάδων (2) Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Εκτέλεση με ένα νήμα Διαιρεί σωστά σε λέξεις τη συμβολοσειρά εισόδου. Pease porridge hot. Pease porridge cold. Pease porridge in the pot Nine days old. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Εκτέλεση με δύο νήματα Ουπς! Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Τι συνέβη; Η strtok αποθηκεύει τη γραμμή εισόδου δηλώνοντας μια μεταβλητή που αποθηκεύεται ως στατική (static). Με αυτό τον τρόπο, η τιμή της μεταβλητής διατηρείται μεταξύ των κλήσεων της συνάρτησης Δυστυχώς για εμάς, η συμβολοσειρά είναι κοινόχρηστη και όχι ιδιωτική. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Τι συνέβη; Προφανώς λοιπόν, η κλήση της strtok από το νήμα 0 με την τρίτη γραμμή εισόδου αντικατέστησε τα περιεχόμενα που είχαν τοποθετηθεί στη μεταβλητή μετά την κλήση της strtok από το νήμα 1 με τη δεύτερη γραμμή εισόδου. Η συνάρτηση strtok δεν είναι ασφαλής για νημάτωση: όταν την καλούν πολλά νήματα ταυτόχρονα, η έξοδος που παράγει μπορεί να μην είναι σωστή. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Άλλες επισφαλείς συναρτήσεις βιβλιοθήκης της C Τέτοια είναι η γεννήτρια τυχαίων αριθμών random στην stdlib.h … και η συνάρτηση μετατροπής χρόνου localtime στην time.h. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συναρτήσεις «επανεισόδου» (ασφαλείς για νημάτωση) Σε κάποιες περιπτώσεις, το πρότυπο της C καθορίζει παραλλαγές αυτών των συναρτήσεων, οι οποίες είναι ασφαλείς για νημάτωση. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συμπερασματικά σχόλια (1) Το νήμα (thread) στον προγραμματισμό κοινόχρηστης μνήμης είναι το ανάλογο της διεργασίας (process) στον προγραμματισμός κατανεμημένης μνήμη. Όμως, τα νήματα είναι συνήθως «ελαφρύτερα» από μια πλήρη διεργασία. Στα προγράμματα Pthreads όλα τα νήματα έχουν πρόσβαση στις καθολικές μεταβλητές, ενώ οι τοπικές μεταβλητές είναι συνήθως ιδιωτικές στα νήματα που εκτελούν τη συνάρτηση. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συμπερασματικά σχόλια (2) Όταν η μη ντετερμινιστική συμπεριφορά οφείλεται σε πολλά νήματα που προσπαθούν να προσπελάσουν έναν κοινόχρηστο πόρο, όπως μια κοινόχρηστη μεταβλητή ή ένα κοινόχρηστο αρχείο, τουλάχιστον μία από αυτές τις προσπελάσεις προκαλεί την τροποποίηση του πόρου, και οι ταυτόχρονες προσπελάσεις μπορούν να οδηγήσουν σε λανθασμένα αποτελέσματα, τότε λέμε ότι έχουμε συνθήκη ανταγωνισμού (race condition). Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συμπερασματικά σχόλια (3) Κρίσιμο τμήμα (critical section) είναι ένα μπλοκ κώδικα που ενημερώνει έναν κοινόχρηστο πόρο ο οποίος επιτρέπεται να τροποποιείται μόνο από ένα νήμα σε κάθε χρονική στιγμή. Επομένως, η εκτέλεση του κώδικα ενός κρίσιμου τμήματος πρέπει ουσιαστικά να γίνεται σειριακά. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συμπερασματικά σχόλια (4) Η αναμονή σε εγρήγορση (busy waiting) υλοποιείται με τη χρήση μιας μεταβλητής σήμανσης και ενός βρόχου while με κενό σώμα εντολών. Προκαλεί σημαντική σπατάλη κύκλων CPU. Μπορεί επίσης να αποδειχτεί αναξιόπιστη όταν είναι ενεργή η βελτιστοποίηση του εκτελέσιμου κώδικα από τον μεταγλωττιστή. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συμπερασματικά σχόλια (5) Για την αποφυγή ανταγωνιστικών προσπελάσεων στα κρίσιμα τμήματα μπορεί να χρησιμοποιηθεί ένα mutex. Είναι ένα είδος κλειδώματος του κρίσιμου τμήματος, αφού τα mutex φροντίζουν για την αμοιβαία αποκλειστική προσπέλαση ενός κρίσιμου τμήματος. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συμπερασματικά σχόλια (6) Ο σηματοφορέας (semaphore) είναι ένας ακόμα τρόπος αποφυγής διενέξεων κατά την προσπέλαση κρίσιμων τμημάτων. Είναι ένας μη προσημασμένος ακέραιος (unsigned int) συσχετισμένος με δύο λειτουργίες, τις sem_wait και sem_post. Οι σηματοφορείς είναι ισχυρότεροι από τα mutex αφού ως αρχική τιμή μπορούν να πάρουν οποιονδήποτε θετικό ακέραιο. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συμπερασματικά σχόλια (7) Φράγμα (barrier) είναι ένα σημείο στον κώδικα ενός προγράμματος όπου τα νήματα μπλοκάρονται μέχρι να φτάσουν όλα τους στο συγκεκριμένο σημείο. Ένα κλείδωμα ανάγνωσης-εγγραφής χρησιμοποιείται όταν είναι ασφαλής η ταυτόχρονη ανάγνωση μιας δομής δεδομένων από πολλά νήματα, αλλά αν κάποιο νήμα χρειάζεται να την τροποποιήσει, δηλαδή να γράψει στη δομή δεδομένων, τότε η προσπέλαση της δομής πρέπει να επιτρέπεται μόνο στο συγκεκριμένο νήμα κατά τη διάρκεια της τροποποίησης. Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.
Συμπερασματικά σχόλια (8) Μερικές συναρτήσεις της C διατηρούν κάποιες τιμές μεταξύ των κλήσεών τους δηλώνοντας αντίστοιχες στατικές μεταβλητές. Αυτή η τακτική μπορεί να οδηγήσει σε σφάλματα όταν μια τέτοια συνάρτηση χρησιμοποιείται από πολλά νήματα. Τέτοιες συναρτήσεις δεν είναι ασφαλείς για νημάτωση (thread-safe). Copyright © 2010, 2015, Elsevier Inc., Klidarithmos Publications. All rights Reserved.