Λειτουργικά Συστήματα

Slides:



Advertisements
Παρόμοιες παρουσιάσεις
Λειτουργικό Σύστημα (Operating System) 1o μέρος
Advertisements

ΧΡΟΝΟΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΔΙΕΡΓΑΣΙΩΝ
ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Ι
Συλλογές, Στοίβες και Ουρές Σε πολλές εφαρμογές μας αρκεί η αναπαράσταση ενός δυναμικού συνόλου με μια δομή δεδομένων η οποία δεν υποστηρίζει την αναζήτηση.
Εφαρμογές Υπολογιστών Ά Λυκείου Κεφ. 4 Λογισμικό Συστήματος
Προγραμματισμός Ι Προτάσεις ελέγχου ροής Ο πιο συνηθισμένος τρόπος εκτέλεσης είναι ο ακολουθιακός: δύο ή περισσότερες προτάσεις βρίσκονται διατεταγμένες.
Νήματα στη Java Καρακασίδης Αλέξανδρος Καστίδου Γεωργία Παπαφώτη Μαρία
Συστήματα εισόδου/εξόδου
Η επιστήμη των υπολογιστών
Λειτουργικά Συστήματα
Λειτουργικά Συστήματα
ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ
Υλοποίηση μεταφραστή C με επεκτάσεις OpenMP Λεοντιάδης Ηλίας Τζούμας Γεώργιος Πτυχιακή εργασία Τελική παρουσίαση Υπεύθυνος καθηγητής Β. Β. Δημακόπουλος.
ΛΟΓΙΣΜΙΚΟ ΣΥΣΤΗΜΑΤΟΣ Κεφάλαιο 4 ο Ελληνογαλλική Σχολή Καλαμαρί - Τίκβα Χριστίνα.
Το υλικο του Υπολογιστη
Κεφάλαιο 1ο: ΒΑΣΙΚΕΣ ΕΝΝΟΙΕΣ ΤΩΝ ΛΕΙΤΟΥΡΓΙΚΩΝ ΣΥΣΤΗΜΑΤΩΝ
Διαδικασία ανάπτυξης Προσδιορισμός απαιτήσεων Αρχιτεκτονικός Σχεδιασμός Λεπτομερής Σχεδιασμός Κωδικοποίηση Έλεγχος Παράδοση Συστήματος Λειτουργία - Συντήρηση.
ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Ι
Λογισμικο συστηματοσ Κεφάλαιο 4ο
Κλασσικά Προβλήματα Επικοινωνίας Σύνδρομων Διεργασιών
Επικοινωνία μεταξύ Διεργασιών και Σύνδρομες Διεργασίες
Κεφάλαιο 6 Threads. 2 Στον παραδοσιακό προγραμματισμό όταν ένα πρόγραμμα εκτελείται ονομάζεται process (διεργασία) και οι εντολές του εκτελούνται σειριακά.
ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Ι
ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Ι
NIKOΛΑΟΣ ΝΤΙΡΛΗΣ 5ο ΦΡΟΝΤΙΣΤΗΡΙΟ ΑΙΘΟΥΣΑ Β4 1.  Ένα thread έχει: ID, program counter, register set, stack  Μοιράζεται με τα άλλα threads της ίδιας διεργασίας.
5. Αμοιβαίος αποκλεισμός
Νήματα Οι διεργασίες έχουν τα παρακάτω συστατικά:
Λειτουργικά Συστήματα ΑΔΙΕΞΟΔΑ. 3.1 Εισαγωγή  Αδιέξοδο = ένα σύνολο από διεργασίες που δημιουργούν μια κυκλική αλυσίδα όπου κάθε process στην αλυσίδα.
Τι είναι διεργασία Ένα πρόγραμμα σε εκτέλεση Η διεργασία περιλαμβάνει:
Διαχείριση μνήμης Υπόβαθρο Εναλλαγή Συνεχής κατανομή Σελιδοποίηση
ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ
Κατανεμημένα Συστήματα με Java
ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ 2: ΘΕΜΑΤΑ ΘΕΩΡΗΤΙΚΗΣ ΕΠΙΣΤΗΜΗΣ Η/Υ
Επικοινωνία μεταξύ Διεργασιών και Σύνδρομες Διεργασίες Interprocess Communication and Concurrent Processes.
Πρωτόκολλο αμοιβαίου αποκλεισμού (mutual exclusion) για δύο διεργασίες-CPN Tools Νάνος Λέανδρος 156 Τζιαλαμάνη Βιργινία 166.
ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ 2: ΘΕΜΑΤΑ ΘΕΩΡΗΤΙΚΗΣ ΕΠΙΣΤΗΜΗΣ Η/Υ
Εθνικό και Καποδιστριακό Πανεπιστήμιο Αθηνών – Τμήμα Πληροφορικής και Τηλεπικοινωνιών 1 Κεφάλαιο 4 Σημασιολογία μιας Απλής Προστακτικής Γλώσσας Προπτυχιακό.
Κεφάλαιο 10 – Υποπρογράμματα
JAVA: Threads Θ. Βαρβαρίγου Καθηγ. ΕΜΠ Τηλ
RPC Multithreaded voting system Γεωργόπουλος Άλκης Κολωνιάρη Γεωργία Κοντογιώργης Τάσος Λεοντιάδης Ηλίας Πετράκης Γιάννης.
Threads Στον παραδοσιακό προγραμματισμό όταν ένα πρόγραμμα εκτελείται ονομάζεται process (διεργασία) και οι εντολές του εκτελούνται σειριακά η μία μετά.
Εφαρμογές Υπολογιστών Ά Λυκείου Κεφ. 4 Λογισμικό Συστήματος
Διεργασίες.
Νήματα με την χρήση των Posix Threads (pthreads)‏.
ΕΝΟΤΗΤΑ 2 – Κεφάλαιο 5: Γνωριμία με το Λογισμικό
Νήματα Εκτέλεσης – Συγχρονισμός Διεργασιών σε Κοινή Μνήμη
1 Αδιέξοδα Μοντέλο συστήματος Χαρακτηρισμός αδιεξόδου Μέθοδοι διαχείρισης αδιεξόδων Πρόληψη Αποφυγή Ανίχνευση.
Λειτουργικά Συστήματα
ΕΙΣΑΓΩΓΉ ΣΤΗΝ ΠΛΗΡΟΦΟΡΙΚΉ ΝΊΚΟΣ ΠΑΠΑΔΆΚΗΣ ΛΟΓΙΣΜΙΚΟ ΤΟΥ ΗΛΕΚΤΡΟΝΙΚΟΥ ΥΠΟΛΟΓΙΣΤΗ.
1 Λειτουργικά Συστήματα Ενότητα 4 : Αρχιτεκτονικές ΛΣ Δημήτριος Λιαροκάπης Ελληνική Δημοκρατία Τεχνολογικό Εκπαιδευτικό Ίδρυμα Ηπείρου.
ΠΑΡΑΔΕΙΓΜΑ: ΤΑ ΕΠΙΠΕΔΑ ΥΛΙΚΟΥ – ΛΟΓΙΣΜΙΚΟΥ ΣΕ ΕΝΑΝ ΥΠΟΛΟΓΙΣΤΗ.
ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Ι
ΜΕΤΑΒΛΗΤΕΣ-ΣΤΑΘΕΡΕΣ -ΕΚΦΡΑΣΕΙΣ
Κατανεμημένα Συστήματα
Συγχρονισμός Διεργασιών
Java DataBase Connectivity
Τι είναι διεργασία Ένα πρόγραμμα σε εκτέλεση Η διεργασία περιλαμβάνει:
Κατηγορίες και Προδιαγραφές Λογισμικού Η/Υ (Software)
Ανάπτυξη Μοντέλων Διακριτών Συστημάτων Μέρος Β
Λειτουργικά Συστήματα και Ασφάλεια Πληροφοριακών Συστημάτων ΔΙΕΡΓΑΣΙΕΣ
Αµοιβαίος αποκλεισµός
Εισαγωγή στα Λειτουργικά Συστήματα (ΛΣ) Operating Systems (OS)
Διπλωματική Εργασία για το Μεταπτυχιακό Δίπλωμα Ειδίκευσης
Διεργασίες Διεργασίες Διαδιεργασιακή Επικοινωνία (IPC)
Κεφάλαιο 10 Streams.
ΤΕΙ Ηρακλείου Τμήμα Εφαρμοσμένης Πληροφορικής και Πολυμέσων
ΔΙΕΡΓΑΣΙΕΣ.
ΣΥΓΧΡΟΝΑ ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Τρίτη Έκδοση ANDREW S
Ιστορική Αναδρομή Λειτουργικών Συστημάτων (ΛΣ) Εισαγωγή : ο πυρήνας (kernel) / ο φλοιός (shell) Β ΕΠΑΛ
Λήψη Αποφάσεων και Συναρτήσεις Ελέγχου
Μεταγράφημα παρουσίασης:

Λειτουργικά Συστήματα Νήματα-Συγχρονισμός

Για τη δημιουργία των διαφανειών έχει χρησιμοποιηθεί υλικό από τις διαφάνειες παραδόσεων των Π.Λάμψας & Σ. Λάλης για το μάθημα Λειτουργικά Συστήματα Παν. Θεσ.

Εισαγωγή Επισκόπηση Μοντέλα πολλαπλών νημάτων (Multithreading Models) Θέματα νημάτων (Threading Issues) Pthreads και νήματα σε μερικά δημοφιλή ΛΣ

Η Έννοια της Διεργασίας (και) Γιατί οι Διεργασίες δεν είναι Αρκετές Η Έννοια της Διεργασίας (και) Γιατί οι Διεργασίες δεν είναι Αρκετές Η διεργασία είναι κυρίως μια λογική έννοια, η οποία στην πράξη υλοποιείται με τον μηχανισμό της διεργασίας σε επίπεδο ΛΣ. Μια λογική διεργασία μπορεί να αντιστοιχεί σε μια (ή περισσότερες) διεργασίες του ΛΣ Τι γίνεται όμως αν μια λογική διεργασία χρειάζεται να υποστηρίξει «ταυτόχρονη» εκτέλεση κώδικα;

Η Έννοια της Διεργασίας (και) Γιατί οι Διεργασίες δεν είναι Αρκετές Η Έννοια της Διεργασίας (και) Γιατί οι Διεργασίες δεν είναι Αρκετές Μπορεί να δημιουργηθούν πολλές διεργασίες (ΛΣ) που συνεργάζονται για τον κοινό σκοπό (της λογικής διεργασίας) Όμως ακόμα και αν οι διεργασίες δημιουργηθούν έτσι ώστε να επικοινωνούν (αποδοτικά) μέσω κοινής μνήμης, το σύστημα επιβαρύνεται λόγω των επιπρόσθετων εναλλαγών περιβάλλοντος λειτουργίας (context switch) που πραγματοποιούνται

Νήματα Τα νήματα (νήματα ελέγχου), ονομάζονται και ελαφρές διεργασίες (lightweight processes – LWPs), είναι ξεχωριστές ροές του ίδιου προγράμματος που εκτελούνται μέσα σε μια λογική διεργασία Τα νήματα μιας διεργασίας ανήκουν πάντα στον ίδιο χρήστη

Νήματα Λειτουργούν (στην ουσία) όπως και οι διεργασίες, δεν είναι όμως πραγματικά ανεξάρτητες εκτελέσεις, καθώς: έχουν τα ίδια δικαιώματα πρόσβασης σε πόρους μοιράζονται τους ίδιους πόρους (δεδομένα, κώδικα, ανοικτά αρχεία, σήματα, … ακόμα και τον χρόνο της ΚΜΕ) μοιράζονται την ίδια μνήμη!

Thread Switch vs Context Switch Για κάθε νήμα διατηρείται ξεχωριστή κατάσταση εκτέλεσης, δηλαδή μετρητής προγράμματος, τιμές των καταχωρητών και στοίβα Η εναλλαγή μεταξύ νημάτων (thread switch) ισοδυναμεί στην πράξη με απλή εναλλαγή κατάστασης ΚΜΕ (register set switch) και όχι με πραγματική εναλλαγή περιβάλλοντος λειτουργίας (context switch) Κατά το thread switch δεν πραγματοποιούνται λειτουργίες διαχείρισης μνήμης και δικαιωμάτων πρόσβασης, με αποτέλεσμα το thread switch να είναι πολύ πιο γρήγορο από το context switch

Διεργασίες και Νήματα

Πλεονεκτήματα Χρήσης Νημάτων (αντί Συνεργαζομένων Διεργασιών) Απόκριση / απόδοση συστήματος Διαμοιρασμός πόρων (Resource Sharing) Οικονομία πόρων Εκμετάλλευση αρχιτεκτονικών πολλαπλών επεξεργαστών Πρόβλημα: Έλεγχος συγχρονισμού (concurrency control problems)

Υλοποίηση Νημάτων σε Επίπεδο Χρήστη (User Threads) Η διαχείριση των νημάτων γίνεται από βιβλιοθήκες που εκτελούνται σε κατάσταση χρήστη (user mode). Αποφεύγεται η επικοινωνία με το σύστημα/πυρήνα (δεν πραγματοποιούνται κλήσεις συστήματος) Τα νήματα εκτελούνται μέσα από μια κοινή διεργασία Ένα νήμα αφήνει την ΚΜΕ με κλήση της ρουτίνας εναλλαγής, με λειτουργία που προκαλεί έμμεσα εναλλαγή ή με την λήξη ενός μετρητή Συνήθως δεν υποστηρίζεται κατανομή του χρόνου εκτέλεσης της διεργασίας στα διάφορα νήματα που έχει μέσα της Παραδείγματα: POSIX pthreads, Mach C-threads, Solaris threads

Νήματα σε Επίπεδο Χρήστη (συνέχεια) Πλεονεκτήματα: Τα νήματα χρήστη εναλλάσσονται (θεωρητικά) γρηγορότερα από τα νήματα πυρήνα. Ωστόσο, στην πράξη, καλές υλοποιήσεις νημάτων σε επίπεδο πυρήνα [Linux] εναλλάσσονται με συναφή απόδοση Μειονεκτήματα: Ένα νήμα μπορεί να μονοπωλήσει τον χρόνο εκτέλεσης μιας διεργασίας (λιμοκτονία (starvation) των υπολοίπων νημάτων) Δεν γίνεται εκμετάλλευση της συμμετρικής πολυεπεξεργασίας Όταν μπλοκαριστεί ένα νήμα μέσα σε κάποια λειτουργία Ι/Ο τότε μπλοκάρονται όλα τα νήματα που εκτελούνται μέσα στην ίδια διεργασία (γιατί το ΛΣ δεν «γνωρίζει» την ύπαρξη τους)

Υλοποίηση Νημάτων σε Επίπεδο Συστήματος/Πυρήνα (Kernel Threads) Τα νήματα πυρήνα υλοποιούνται στον πυρήνα του ΛΣ, και οι αντίστοιχες βιβλιοθήκες χρησιμοποιούν κλήσεις συστήματος Σε αυτή την περίπτωση ο πυρήνας χρονοδρομολογεί κάθε νήμα εντός της μονάδας χρόνου που αναλογεί στην διεργασία μέσα στην οποία εκτελούνται τα νήματα Υπάρχει περισσότερος φόρτος στο σύστημα λόγω της εναλλαγής κατάστασης χρήστη <-> σύστημα (user mode <-> system mode) και την διαχείριση πιο πολύπλοκων περιβαλλόντων, αλλά οι αρχικές μετρήσεις απόδοσης δείχνουν αμελητέα αύξηση στο χρόνο Παραδείγματα: Windows 95/98/NT/2000, Solaris,Tru64 UNIX, BeOS, Linux

Νήματα σε Επίπεδο Πυρήνα (συνέχεια) Πλεονεκτήματα: Αποτροπή της μονοπώλησης της μονάδας χρόνου μιας διεργασίας από ένα νήμα (ενώ υπάρχουν και άλλα προς εκτέλεση) Το μπλοκάρισμα ενός νήματος σε Ι/Ο δεν συνεπάγεται μπλοκάρισμα και των άλλων νημάτων που εκτελούνται μέσα στην ίδια διεργασία Μια διεργασία μπορεί να εκμεταλλευτεί (πιο εύκολα) τη συμμετρική πολυεπεξεργασία του ΛΣ και να τρέχει γρηγορότερα με κάθε ΚΜΕ που προστίθεται στο σύστημα Μειονεκτήματα: Ταχύτητα εναλλαγής νημάτων

Μοντέλα Πολλαπλών Νημάτων (Multithreading Models) Ανάλογα με το αν το ΛΣ υποστηρίζει νήματα σε επίπεδο πυρήνα αλλά και το πως αυτά αντιστοιχίζονται σε νήματα επιπέδου χρήστη, υπάρχουν διάφορες προσεγγίσεις υλοποίησης: Πολλά σε Ένα (Many-to-One) Ένα προς Ένα (One-to-One) Πολλά προς Πολλά (Many-to-Many)

Πολλά σε Ένα (Many-to-One) Πολλά νήματα επιπέδου χρήστη αντιστοιχούν σε ένα νήμα πυρήνα Χρησιμοποιείται σε συστήματα που δεν υποστηρίζουν νήματα πυρήνα

Μοντέλο Πολλά σε Ένα

Ένα προς Ένα (One-to-One) Κάθε νήμα χρήστη αντιστοιχεί σε ένα νήμα πυρήνα Παραδείγματα: - Windows 95/98/NT/2000 - OS/2

Μοντέλο Ένα προς Ένα

Μοντέλο Πολλά προς Πολλά Επιτρέπει σε πολλά νήματα χρήστη να αντιστοιχιστούν σε πολλά νήματα πυρήνα Επιτρέπει στο ΛΣ να δημιουργήσει επαρκή αριθμό νημάτων πυρήνα Solaris 2 Windows NT/2000 με το πακέτο ThreadFiber

Μοντέλο Πολλά προς Πολλά (συνέχεια)

Θέματα Νημάτων (Threading Issues) Σημασιολογία των κλήσεων συστήματος fork() και exec() Δεξαμενές νημάτων (Thread pools) Ακύρωση νημάτων (Thread cancellation) Χειρισμός σημάτων (Signal handling) Δεδομένα σχετικά με τα νήματα (Thread specific data)

Pthreads (POSIX Threads) Μια τυποποίηση POSIX (IEEE 1003.1c) API για δημιουργία και συγχρονισμό νημάτων σε περιβάλλον Unix To API προσδιορίζει τους τύπους (types), τις επικεφαλίδες των ρουτινών (interfaces), και την συμπεριφορά των ρουτινών της αντίστοιχης βιβλιοθήκης Η υλοποίηση της βιβλιοθήκης εναπόκειται στο ΛΣ

Νήματα στο Solaris 2

Διεργασίες στο Solaris 2

Νήματα στα Windows 2000 Υλοποιούν την αντιστοίχηση «Ένα προς Ένα» Κάθε νήμα περιέχει: ένα thread id ένα σύνολο από καταχωρητές (register set) ξεχωριστές στοίβες για το χρήστη και τον πυρήνα ιδιωτικό χώρο αποθήκευσης δεδομένων

Νήματα στο Linux (Linux Threads) To Linux αναφέρεται σε αυτά ως εργασίες (tasks) παρά ως νήματα Η δημιουργία νημάτων γίνεται μέσω της κλήσης συστήματος clone() H Clone() επιτρέπει σε μια εργασία παιδί να μοιράζεται το χώρο διευθύνσεων της πατρικής εργασίας (διεργασίας)

Νήματα στην Java Τα νήματα στη Java μπορούν να δημιουργηθούν μέσω: Επέκτασης του Thread class Υλοποίησης της διεπαφής Runnable Την διαχείριση των νημάτων στη Java αναλαμβάνει η JVM

Κατάσταση Νημάτων στην Java

Νήματα στην Java Δέστε παραδείγματα: Driver.java Driver2.java SleepMessages.java SimpleThreads.java

Συγχρονισμός Διεργασιών σε Κοινή Μνήμη (Process Synchronization)

Εισαγωγή Θεωρητικό υπόβαθρο Το πρόβλημα του κρίσιμου τμήματος (the critical-section problem) Υλικό συγχρονισμού Σηματοφορείς ή σημαφόροι (semaphores) Κλασικά προβλήματα συγχρονισμού Κρίσιμες περιοχές (critical regions) Ελεγκτές/παρακολουθητές (monitors)

Θεωρητικό Υπόβαθρο Η ταυτόχρονη πρόσβαση σε κοινά δεδομένα μπορεί να οδηγήσει σε ασυνέπεια δεδομένων (data inconsistency) Το πρόβλημα της συνέπειας υφίσταται στα νήματα και στις διεργασίες(*) με κοινή μνήμη που έχουν ταυτόχρονη πρόσβαση σε όλες τις καθολικές μεταβλητές και τα δυναμικά δεδομένα ενός προγράμματος Παρόμοιο πρόβλημα αντιμετωπίζει ο κώδικας του συστήματος του οποίου η εκτέλεση μπορεί να διακοπεί από τις ρουτίνες χειρισμού διακοπών (interrupt handlers) που με την σειρά τους μπορεί να κάνουν κλήσεις συστήματος (που και αυτές μπορεί να διακοπούν ...) (*) Σε αυτή την ενότητα χρησιμοποιούμε τον (γενικότερο) όρο διεργασία, ακόμα και όταν αναφερόμαστε σε νήματα

Πρόσβαση σε Κοινή Μεταβλητή (Shared variable) Έστω πως δύο διεργασίες εκτελούν τον παρακάτω κώδικα: int i=0; /* κοινή μεταβλητή */ void body { i++; } Ποιά η τιμή της μεταβλητής i αφού εκτελεσθούν οι διεργασίες; Μπορεί να είναι 1 ή 2, δεν το ξέρουμε εκ των προτέρων! Κάθε εκτέλεση μπορεί να δίνει διαφορετικό αποτέλεσμα!

Γιατί; Το πρόβλημα είναι πως η εκτέλεση της εντολής i++ δεν είναι (εγγυημένα) ατομική (atomic) δηλαδή χωρίς να υπάρχει πιθανότητα διακοπής της Η εντολή i++ μεταφράζεται σε γλώσσα μηχανής ως εξής: regX = mem[i_adr]; regX = regX+1; memy[i_adr] = regX; Η σειριακή εκτέλεση του κώδικα των διεργασιών δίνει διαφορετικό αποτέλεσμα από μια διαπλεκόμενη (interleaved) εκτέλεσή του Η εκτέλεση εξαρτάται από την (τυχαία) χρονοδρομολόγηση του ΛΣ

Σενάρια Εκτέλεσης Αρχικά η μεταβλητή i έχει την τιμή 0. Σενάριο Α thread 1: reg1 = mem[i_adr]; thread 1: reg1 = reg+1; thread 2: reg2 = mem[i_adr]; thread 2: reg2 = reg2+1; thread 2: mem[i_adr] = reg2; thread 1: mem[i_adr] = reg1; Η μεταβλητή i έχει την τιμή 1 Σενάριο B thread 1: reg1 = mem[i_adr]; thread 1: reg1 = reg+1; thread 1: mem[i_adr] = reg1; thread 2: reg2 = mem[i_adr]; thread 2: reg2 = reg2+1; thread 2: mem[i_adr] = reg2; Η μεταβλητή i έχει την τιμή 2

Κατάσταση Συναγωνισμού (Race Condition) Κατάσταση Συναγωνισμού: Η κατάσταση όπου πολλές διεργασίες προσπελαύνουν και χειρίζονται ταυτόχρονα κοινά δεδομένα Η τελική τιμή των κοινών δεδομένων εξαρτάται από το πως θα δρομολογηθεί η επιμέρους εκτέλεσης του κώδικα των διεργασιών Για την αποτροπή καταστάσεων συναγωνισμού, οι διεργασίες με κοινή μνήμη πρέπει να συγχρονίζονται

Το Πρόβλημα του Κρίσιμου Τμήματος (critical section problem) Ένας αριθμός από Ν διεργασίες εκτελούνται ταυτόχρονα μεταξύ τους και επιθυμούν να χρησιμοποιήσουν κάποια κοινά δεδομένα Κάθε διεργασία έχει ένα τμήμα κώδικα που καλείται κρίσιμο τμήμα (critical section), στο οποίο προσπελαύνονται τα κοινά δεδομένα Πρόβλημα: Διασφάλισε ότι όταν μια διεργασία εκτελεί κώδικα στο κρίσιμο τμήμα της, καμία άλλη διεργασία δεν θα να εκτελέσει στο κρίσιμο τμήμα της

Αφηρημένη Δομή των Διεργασιών while (1) { Κανονικός Κώδικας (δεν τίθεται θέμα συγχρονισμού) Κρίσιμο Τμήμα (critical section) }

Οι 3 Απαιτήσεις της Λύσης του Κρίσιμου Τμήματος 1. Αμοιβαίος αποκλεισμός (mutual exclusion): Αν η μια διεργασία εκτελεί κώδικα στο κρίσιμο τμήμα της, τότε καμία άλλη διεργασία δεν εκτελεί κώδικα στο κρίσιμο τμήμα της 2. Πρόοδος (progress): Αν δεν υπάρχει διεργασία που να βρίσκεται μέσα στο κρίσιμο τμήμα της και υπάρχουν διεργασίες που επιθυμούν να εισέλθουν στο κρίσιμο τμήμα τους, τότε η επιλογή της επόμενης διεργασίας που θα εισέλθει στο κρίσιμο τμήμα της δεν μπορεί να αναβάλλεται επ’ αόριστον

Οι 3 Απαιτήσεις της Λύσης του Κρίσιμου Τμήματος (συνέχεια) 3. Πεπερασμένη Αναμονή (bounded waiting): Πρέπει να υπάρχει ένα όριο στο πλήθος των φορών που επιτρέπεται σε άλλες διεργασίες να εισέλθουν στο κρίσιμο τμήμα τους, αφότου μια διεργασία έχει εκδώσει αίτηση να εισέλθει στο κρίσιμο τμήμα της και μέχρι η αίτηση αυτή να ικανοποιηθεί Υποθέτουμε ότι κάθε διεργασία εκτελείται με μη μηδενική ταχύτητα Δεν μπορεί να γίνει καμία υπόθεση η οποία να αφορά τη σχετική ταχύτητα των διαφόρων διεργασιών, ή το πλήθος των επεξεργαστών στους οποίους εκτελούνται οι διεργασίες

Πιο Λεπτομερής Δομή των Διεργασιών while (1) { Κανονικός Κώδικας (δεν τίθεται θέμα συγχρονισμού) Κρίσιμο Τμήμα (critical section) } Κώδικας Εισόδου (entry code) Κώδικας Εξόδου (exit code)

Αλγόριθμος 1 (δύο Διεργασίες) Κοινή μεταβλητή turn (η διεργασία Pi εισέρχεται στο ΚΤ μόνο όταν turn=i): shared vars: int turn=0; process body: while (1) { while (turn!=i) {} /* entry code */ do_critical_section(); turn=(i+1)%2; /* exit code */ } Ικανοποιεί τον αμοιβαίο αποκλεισμό, αλλά όχι την πρόοδο (γιατί;)

Αλγόριθμος 2 (δύο Διεργασίες) Κοινή μεταβλητή boolean flag[2] (η διεργασία Pi εισέρχεται στο ΚΤ μόνο όταν flag[i]= true): shared vars: boolean flag[2]={false,false}; process body: while (1) { flag[i]=true; /* entry code */ while (flag[(i+1)%2]) {} do_critical_section(); flag[i]=false; /* exit code */ } Ικανοποιεί τον αμοιβαίο αποκλεισμό, αλλά όχι την πρόοδο (γιατί;)

Αλγόριθμος Paterson (δύο Διεργασίες) Συνδυασμός των δύο προηγουμένων αλγορίθμων: shared vars: int turn=0; boolean flag[2]={false,false}; process body: while (1) { flag[i]=true; turn=(i+1)%2; /* entry code */ while ( (flag[(i+1)%2]) && (turn=(i+1)%2) ) {} do_critical_section(); flag[i]=false; /* exit code */ } Ικανοποιεί και τις τρεις απαιτήσεις (γιατί;)

Αλγόριθμός για πολλές Διεργασίες Ο Αλγόριθμος Bakery Πριν την είσοδό της στο κρίσιμο τμήμα, μια διεργασία Pi λαμβάνει έναν αριθμό σειράς ti. Το σύστημα αριθμοδότησης δημιουργεί αριθμούς σειράς με αύξουσα σειρά αρίθμησης, π.χ., 1,2,3,3,3,4,5… Η διεργασία με τον μικρότερο αριθμό σειράς εισέρχεται στο κρίσιμο τμήμα Αν οι διεργασίες Pi και Pj έχουν τον ίδιο αριθμό σειράς, αν i < j, τότε εξυπηρετείται πρώτα η Pi, αλλιώς πρώτα η Pj Συμβολισμοί: (a,b) before (c,d) <=> ((a < c) || ((a = c) && (b < d)) max (a0,…, an-1) = k, k  ai για i = 0,…, n – 1

Ο Αλγόριθμος Bakery (συνέχεια) shared vars: boolean choosing[n]={false,…,false}; int t[n]={0,…,0}; process body: while (1) { choosing[i] = true; t[i] = max(t[0],t[1],…, t[n-1])+1; choosing[i] = false; for (j=0; j<n; j++) { while (choosing[j]) {} while ((t[j]!=0) && (t[j],j) before (t[i],i)) {} } do_critical_section(); t[i] = 0; Παραλαβή αριθμού σειράς Έλεγχος προτεραιότητας

Υλικό Συγχρονισμού (Synchronization Hardware) Μερικοί επεξεργαστές υποστηρίζουν την εξής εντολή TestAndSet για τον ατομικό έλεγχο και αλλαγή μιας θέσης μνήμης (μεταβλητής) Η συμβολική υλοποίηση της εντολής δίνεται ως εξής: boolean TestAndSet(boolean *target) { boolean value_read = *target; *target = true; return value_read; } Η εντολή εκτελείται χωρίς διακοπή (εγγυημένα)

Αλγόριθμος Κρίσιμου Τμήματος με Χρήση της TestandSet shared vars: boolean lock=false; process body: while (1) { while (TestAndSet(&lock)) {} do_critical_section(); lock = false; }

Υλικό Συγχρονισμού (συνέχεια) Εξατομικευμένη εναλλαγή δύο μεταβλητών void Swap(boolean *a, boolean *b) { boolean tmp; tmp = *a; *a = *b; *b = tmp; }

Αλγόριθμος Κρίσιμου Τμήματος με Χρήση της Swap shared vars: boolean lock=false; process body: boolean key; while (1) { key=true; do {Swap(&lock,&key);} while (key); do_critical_section(); lock = false; }

Σημαφόροι ή Σηματοφορείς (Semaphores) Εργαλείο συγχρονισμού που δεν απαιτεί ενεργό αναμονή (busy waiting) της διεργασίας, εκτελώντας κάποιες εντολές σε βρόγχο Μια μεταβλητή τύπου s σηματοφορέα μπορεί να προσπελαστεί μέσω δύο ατομικών πράξεων wait (ή down) και signal (ή up), που μπορεί να θεωρηθεί πως υλοποιούνται ως εξής: void wait(int *s) { while (*s<=0) {} *s--; } void signal(int *s) { *s++;

Υλοποίηση Κρίσιμου Τμήματος για n Διεργασίες με Σημαφόρους shared vars: semaphore s=1; process body: while (1) { wait(s); do_critical_section(); signal(s); }

Υλοποίηση Σημαφόρου typedef struct { int sval; /* value of semaphore */ struct procQ pq;/* queue of waiting processes */ } semaphore; void init(semaphore *s, int val) { s->sval=val; initQ(s->pq); }

Υλοποίηση Σημαφόρου (συνέχεια) void wait(semaphore *s) { s->sval--; if (s->sval<0) { addQ(s->pq,thisProcess()); suspend(); } void signal(semaphore *s) { s->sval++; if (s->sval<=0) { resume(rmvQ(s->pq));

Η Σημαφόρος ως ένα Γενικό Εργαλείο Συγχρονισμού Διεργασία Pi Διεργασία Pj … … A wait(flag) signal(flag) B Χρήση της σημαφόρου flag με αρχική τιμή 0 Εκτέλεση του B στην Pj μόνο αφού εκτελεστεί το A στην Pi

Τύποι Σημαφόρων Γενική σημαφόρος (ή σημαφόρος μετρητής) (general or counting semaphore) – μπορεί να έχει μια οποιαδήποτε ακέραια τιμή Δυαδική σημαφόρος (binary semaphore) – μπορεί να παίρνει τιμές μόνο μεταξύ 0 και 1, κάτι που μπορεί να σημαίνει ευκολότερη υλοποίηση Μια γενική σημαφόρος μπορεί να υλοποιηθεί με χρήση δυαδικών σημαφόρων

Κλασικά Προβλήματα Συγχρονισμού Το πρόβλημα της αποθήκης πεπερασμένης χωρητικότητας (bounded-buffer problem) Το πρόβλημα αναγνωστών και εγγραφέων (readers and writers problem) Το πρόβλημα των συνδαιτυμόνων φιλοσόφων (dining philosophers problem)

Αποθήκη Πεπερασμένης Χωρητικότητας Κοινά δεδομένα: semaphore mutex,full,empty; Αρχικοποίηση: init(&mutex,1); init(&empty,n); init(&full,0);

Διεργασία Παραγωγός (producer) while (1) { … παραγωγή αντικειμένου item wait(&empty); wait(&mutex); προσθήκη αντικειμένου item στην αποθήκευση signal(&mutex); signal(&full); }

Διεργασία Καταναλωτής (consumer) while (1) { … wait(&full); wait(&mutex); απομάκρυνση αντικειμένου item από την αποθήκευση signal(&mutex); signal(&empty); κατανάλωση αντικειμένου item }

Αναγνώστες και Εγγραφείς Κοινά δεδομένα: semaphore mutex,write; int readers; Αρχικοποίηση: init(&mutex,1); init(&write,1); readers=0;

Διεργασία Εγγραφέας while (1) { … wait(&write); γράψιμο δεδομένων signal(&write); }

Διεργασία Αναγνώστης while (1) { … wait(&mutex); readers++; if (readers==1) {wait(&write);} signal(&mutex); διάβασμα δεδομένων readers--; if (readers==0) {signal(&write);} }

Οι Συνδαιτυμόνες Φιλόσοφοι Κοινά δεδομένα: semaphore fork[n]; Αρχικοποίηση: init(&fork[0],1); init(&fork[1],1); … init(&fork[n-1],1);

Ο Φιλόσοφος i while (1) { … wait(&fork[i]); wait(&fork[(i+1)%n); επιτέλους τρώμε! signal(&fork[i]); signal(&fork[(i+1)%n]); ας σκεφτούμε λιγάκι } Υπάρχει περίπτωση ο ένας φιλόσοφος να περιμένει τον άλλο σε κύκλο;

Αδιέξοδο και Λιμοκτονία (Deadlock and Starvation) Αδιέξοδο – δύο ή περισσότερες διεργασίες περιμένουν απεριόριστα για ένα γεγονός που μπορεί να προκληθεί μόνο από μια από τις δυο Έστω S και Q δύο σημαφόροι με αρχική τιμή 1 P0 P1 wait(S); wait(Q); wait(Q); wait(S);   signal(S); signal(Q); signal(Q) signal(S); Λιμοκτονία – απεριόριστη αναμονή. Μια διεργασία μπορεί να μην φύγει από την ουρά της σημαφόρου στην οποία έχει ανασταλεί

Κρίσιμες Περιοχές (Critical Regions) Δομή υψηλού επιπέδου για την υποστήριξη του συγχρονισμού κρίσιμων τμημάτων, ως εξής: Μια κοινή μεταβλητή v τύπου T ορίζεται ως: T (shared) v; Η v μπορεί να προσπελαστεί μόνο μέσω της εντολής region: region v when B do S; όπου η διεργασία ελέγχει την συνθήκη B και αν είναι αληθής, τότε εκτελεί την ομάδα εντολών S, διαφορετικά αναστέλλεται μέχρι η συνθήκη B να γίνει αληθής. Τόσο ο έλεγχος της συνθήκης B όσο και η εκτέλεση της ομάδας εντολών S γίνεται ατομικά (το σύστημα εγγυάται πως δεν παρεμβάλλονται άλλες διεργασίες σε αυτή την περιοχή).

Αποθήκη Πεπερασμένης Χωρητικότητας με Κρίσιμες Περιοχές typedef struct { item slots[n]; int in,out,cnt; } buffer; buffer (shared) b; b.cnt=0; b.in=b.out=0; slots[0] slots[n-1] direction of in, out

Αποθήκη Πεπερασμένης Χωρητικότητας (συνέχεια) Διεργασία Παραγωγός while (1) { … item=produce(); region b when (b.cnt<n){ b.slots[b.in]=item; b.in=(b.in+1)%n; b.cnt++; } Διεργασία Καταναλωτής while (1) { … region b when (b.cnt>0){ item=b.slots[b.out]; b.out=(b.out+1)%n; b.cnt--; } consume(item);

Ελεγκτές/Παρακολουθητές (Monitors) Δομή υψηλού επιπέδου που επιτρέπει την ασφαλή πρόσβαση ενός αφηρημένου τύπου δεδομένων μεταξύ ταυτόχρονων διεργασιών monitor monitor-name { δηλώσεις κοινών μεταβλητών procedure P1 (…) {…} procedure P2 (…) {…} procedure Pn (…) {…} { κώδικας αρχικοποίησης } Οι ρουτίνες πρόσβασης Pi εκτελούνται συγχρονισμένα, με εγγυημένο τον αμοιβαίο αποκλεισμό ανάμεσα σε διεργασίες

Ελεγκτές/Παρακολουθητές (συνέχεια) Για να επιτραπεί σε μια διεργασία να περιμένει μέσα σε έναν ελεγκτή, πρέπει να δηλωθεί αντίστοιχη μεταβλητή συνθήκης (condition variable): condition x; Μπορεί να χρησιμοποιηθεί μόνο με τις λειτουργίες wait και signal Η λειτουργία x.wait() σημαίνει ότι η διεργασία αναστέλλεται Η λειτουργία x.signal() εκκινεί (μόνο) μια από τις διεργασίες που έχουν ανασταλεί, αν υπάρχει (διαφορετικά δεν κάνει τίποτα) Η λειτουργία x.signalAll() εκκινεί όλες τις διεργασίες (αν υπάρχουν) που έχουν ανασταλεί μέσω της μεταβλητής x

Αναμονή με Προτεραιότητες Αναμονή υπό συνθήκη (conditional-wait): x.wait(c); c – ακέραιος που ελέγχεται όταν εκτελείται η λειτουργία wait Η τιμή του c (αριθμός προτεραιότητας) αποθηκεύεται με το όνομα της διεργασίας που ανεστάλη Η εκτέλεση της x.signal, ενεργοποιεί τη διεργασία με τη μικρότερη προτεραιότητα

Σχηματική Θεώρηση ενός Ελεγκτή

Ελεγκτής με Μεταβλητές Συνθήκης

Συνδαιτυμόνες Φιλόσοφοι με Ελεγκτή monitor dining_phils { enum {thinking,hungry,eating} state[n]; condition self[n]; void pickup(int i); void putdown(int i); void test(int i); void init() { int i; for (i=0; i<5; i++) {state[i] = thinking;} }

Συνδαιτυμόνες Φιλόσοφοι (συνέχεια) void pickup(int i) { state[i] = hungry; test(i); if (state[i] != eating) { self[i].wait(); } void putdown(int i) { state[i] = thinking; test((i+n-1)%n); /* test left */ test((i+1)%n); /* test right */

Συνδαιτυμόνες Φιλόσοφοι (συνέχεια) void test(int i) { if ( (state[i] == hungry) && (state[(i+n-1)%5] != eating) && (state[(i+1)%n] != eating) ) { state[i] = eating; self[i].signal(); }

Υλοποίηση Ελεγκτών με Σημαφόρους Για κάθε ελεγκτή, καθολικές μεταβλητές: semaphore mutex,next; int next-count; Επιπλέον, για κάθε μεταβλητή συνθήκης, μεταβλητές: semaphore x-sem; int x-count; Αρχικοποίηση του ελεγκτή: init(&mutex,1); init(&next,0); next-count=0; Και αρχικοποίηση για κάθε μεταβλητή συνθήκης: init(&x-sem); x-count=0;

Υλοποίηση Ελεγκτών με Σημαφόρους (συνέχεια) Για κάθε ρουτίνα πρόσβασης Pi, το σώμα της αντικαθίσταται με : procedure Pi (…) { wait(&mutex); κυρίως σώμα της Pi if (next-count > 0) {signal(&next);} else {signal(&mutex);} }

Υλοποίηση Ελεγκτών με Σημαφόρους (συνέχεια) Η λειτουργία x.wait() μπορεί να υλοποιηθεί ως εξής: x-count++; if (next-count > 0) { signal(&next); } else { signal(&mutex); wait(&x-sem); x-count--;

Υλοποίηση Ελεγκτών με Σημαφόρους (συνέχεια) Η λειτουργία x.signal() μπορεί να υλοποιηθεί ως εξής: if (x-count > 0) { next-count++; signal(&x-sem); wait(&next); next-count--; }

Υλοποίηση Ελεγκτών με Σημαφόρους (συνέχεια) Η λειτουργία x.signalAll() μπορεί να υλοποιηθεί ως εξής: if (x-count > 0) { next-count++; for (c=x-count; c > 0; c--) { signal(&x-sem); } wait(&next); next-count--;

Συγχρονισμός στην Java Synchronized, wait/notify/notifyAll Atomic objects & locks Παραδείγματα: AtomicCounter.java SyncronizedCounter.java Drop.java,Producer.java,Consumer.java,ProducerConsumerExample.java Safelock.java