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

Σχετικά έγγραφα
ΙΩΑΝΝΗΣ ΚΩΝΣΤΑΝΤΙΝΟΥ 2ο ΦΡΟΝΤΙΣΤΗΡΙΟ ΠΑΡΑΣΚΕΥΗ 26 ΟΚΤΩΒΡΙΟΥ 2012 ΑΙΘΟΥΣΑ Β4

Πανεπιστήμιο Θεσσαλίας Τμήμα Πληροφορικής

Εργαστήριο ΔΙΕΡΓΑΣΙΕΣ - ΔΙΑΧΕΙΡΙΣΗ

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

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

ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ. Διεργασίες και Νήματα Εργαστηριακές Ασκήσεις

Δημιουργία & Τερματισμός Διεργασιών. Προγραμματισμός II 1

Δημιουργία & Τερματισμός Διεργασιών. Προγραμματισμός II 1

Συγχρονισμός & σηματοφόροι. Προγραμματισμός II 1

Προγραμματισμός συστημάτων UNIX/POSIX

Προγραμματισμός συστημάτων UNIX/POSIX. Διεργασίες (processes)

ΝΗΜΑΤΑ - ΕΡΓΑΣΤΗΡΙΟ 1 - ΣΗΜΕΙΩΣΕΙΣ

Προγραμματισμός συστημάτων UNIX/POSIX

ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ II. Υφαντόπουλος Νικόλαος Υποψήφιος Διδάκτορας Contact:

Μεθόδων Επίλυσης Προβλημάτων

ιεργασίες και νήµατα Προγραµµατισµός ΙΙΙ 1 lalis@inf.uth.gr

Ντίρλης Νικόλαος- ΕΤΥ 2 ο Φροντιστήριο Παρασκευή, 18/10/2013 Β4. Λειτουργικά Συστήματα- Φροντιστήριο 2

Κεφάλαιο , 3.2: Συναρτήσεις II. (Διάλεξη 12)

Θέτοντας και επιστρέφοντας την τιµή της προτεραιότητας διεργασίας

Λύβας Χρήστος Αρχική επιµέλεια Πιτροπάκης Νικόλαος και Υφαντόπουλος Νικόλαος

Εργαστήριο 5 fork(), exec(), signals

Προγραμματισμός συστημάτων UNIX/POSIX. Διαδιεργασιακή επικοινωνία: αγωγοί (IPC inter-process communication: pipes)

Νσίπληρ Νίκορ- ΕΣΤ 4ο ΥΡΟΝΣΙΣΗΡΙΟ Παπαςκετή Β4

Εκφωνήσεις ασκήσεων εργαστηρίου 1

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

Εικονική Μνήμη (Virtual Memory) Προγραμματισμός II 1

2η Εργαστηριακή Άσκηση

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

Λειτουργικά Συστήματα 7ο εξάμηνο, Ακαδημαϊκή περίοδος

Εισαγωγή στον Προγραµµατισµό. Διάλεξη 3 η : Επίλυση Προβληµάτων Χειµερινό Εξάµηνο 2011

Κεφάλαιο , 3.2: Συναρτήσεις II. ( ιάλεξη 12) ιδάσκων: ηµήτρης Ζεϊναλιπούρ

Διδάσκων: Κωνσταντίνος Κώστα Διαφάνειες: Δημήτρης Ζεϊναλιπούρ

Σηματοφόροι (Σηματοφορείς) Ταυτόχρονος Προγραμματισμός 1

ΕΛΛΗΝΙΚΟ ΑΝΟΙΚΤΟ ΠΑΝΕΠΙΣΤΗΜΙΟ

(Κεφάλαιο 2.7 και 12) Αρχεία στην C. (Διάλεξη 15)

Παράλληλη Επεξεργασία

Λειτουργικά Συστήματα (ΗΥ-345) Χειμερινό Εξάμηνο

Εργαστήριο 7 fork(), exec(), signals

Λειτουργικά Συστήματα 7ο εξάμηνο, Ακαδημαϊκό Έτος

Εισαγωγή στον Προγραμματισμό

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

Μεθόδων Επίλυσης Προβλημάτων

Προγραμματισμός Ι. Δυναμική Διαχείριση Μνήμης. Δημήτρης Μιχαήλ. Ακ. Έτος Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Εισαγωγή εκτελέσιμου κώδικα σε διεργασίες

Μεθόδων Επίλυσης Προβλημάτων

ΕΘΝΙΚΟ ΚΑΙ ΚΑΠΟΔΙΣΤΡΙΑΚΟ ΠΑΝΕΠΙΣΤΗΜΙΟ ΑΘΗΝΩΝ ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ & ΤΗΛΕΠΙΚΟΙΝΩΝΙΩΝ ΧΕΙΜΕΡΙΝΟ ΕΞΑΜΗΝΟ ΜΑΘΗΜΑ: ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ

Προγραμματισμός Ι. Είσοδος/Έξοδος. Δημήτρης Μιχαήλ. Ακ. Έτος Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Προγραμματισμός Ι. Προεπεξεργαστής. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Δομημένος Προγραμματισμός. Τμήμα Επιχειρηματικού Σχεδιασμού και Πληροφοριακών Συστημάτων

Συστήματα Παράλληλης και Κατανεμημένης Επεξεργασίας

Προγραμματισμός Η/Υ (ΤΛ2007 )

Επανάληψη για τις Τελικές εξετάσεις. (Διάλεξη 24) ΕΠΛ 032: ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΜΕΘΟΔΩΝ ΕΠΙΛΥΣΗΣ ΠΡΟΒΛΗΜΑΤΩΝ

Μεθόδων Επίλυσης Προβλημάτων

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ Η/Υ Ακαδημαϊκό έτος ΤΕΤΡΑΔΙΟ ΕΡΓΑΣΤΗΡΙΟΥ #4

ΑΣΚΗΣΗ 1: TO ΠΕΡΙΒΑΛΛΟΝ ΕΡΓΑΣΙΑΣ DEV-C++

Σηματοφόροι (Σηματοφορείς) Ταυτόχρονος Προγραμματισμός 1

ΕΡΓΑΣΤΗΡΙΟ 4: Μεταβλητές, Δομές Ελέγχου και Επανάληψης

Εικονική Μνήμη (Virtual Memory) Προγραμματισμός II 1

Α. unsigned int Β. double. Γ. int. unsigned char x = 1; x = x + x ; x = x * x ; x = x ^ x ; printf("%u\n", x); Β. unsigned char

Ενδεικτικές λύσεις και στατιστικά

Προγραμματισμός Η/Υ (ΤΛ2007 )

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

Διεργασίες (Processes)

ΕΚΔΟΣΗ 1.1 ΜΑΙΟΣ, 2018 ΕΙΣΑΓΩΓΗ ΣΤΑ ΚΑΤΑΝΕΜΗΜΕΝΑ ΣΥΣΤΗΜΑΤΑ ΑΛΓΟΡΙΘΜΟΣ POLLING ΚΥΜΑΤΙΚΟΣ ΑΛΓΟΡΙΘΜΟΣ ΕΠΙΜΕΛΕΙΑ: Β. ΤΣΑΚΑΝΙΚΑΣ, Β.

Δομημένος Προγραμματισμός (ΤΛ1006)

Προγραμματισμός Η/Υ (ΤΛ2007 )

Κατανεμημένα και Παράλληλα Συστήματα (εργαστήριο) Παραδείγματα με openmp

ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ. Διαδιεργασιακή Επικοινωνία Εργαστηριακές Ασκήσεις

Επεξεργασία Αρχείων Κειµένου

ΧΑΡΟΚΟΠΕΙΟ ΠΑΝΕΠΙΣΤΗΜΙΟ

Ελεγκτές/Παρακολουθητές (Monitors) Ταυτόχρονος Προγραμματισμός 1

Εξοικείωση με το πρόγραμμα DEV C++ Επικοινωνία Χρήστη - Υπολογιστή

Π. Σταθοπούλου ή Οµάδα Α (Φοιτητές µε µονό αριθµό Μητρώου ) ιδασκαλία : Παρασκευή 11πµ-13µµ ΗΛ7

Διαδιεργασιακή επικοινωνία (inter-process communication IPC) Προγραμματισμός II 1

Λειτουργικά Συστήματα 7ο εξάμηνο, Ακαδημαϊκό Έτος

Γλώσσα Προγραμματισμού C. Προγραμματισμός HY: Γλώσσα Προγραμματισμού C. Γρήγορος Πίνακας Αναφοράς Σύνταξης. Εισήγηση #4. Επαναληπτικές δομές:

Εργαστήριο 9: Αρχεία

Εργαστήριο Λειτουργικών Συστημάτων 8o εξάμηνο, Ροή Υ, ΗΜΜΥ

ΤΕΜ-101 Εισαγωγή στους Η/Υ Εξεταστική Ιανουαρίου 2011 Θέματα Β

Κεφάλαιο 3.1, : Συναρτήσεις I. (Διάλεξη 11)

Λειτουργικά Συστήματα 7ο εξάμηνο, Ακαδημαϊκό Έτος Κανονική Εξέταση Λύσεις

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

Παράλληλη Επεξεργασία

Εργαστήριο 14. Συγχρονισμός Νημάτων (χρήση pthread_mutex_t, pthread_cond_t)

Διάλεξη 18η: Διαχείρηση Αρχείων

IPC System V. Προγραμματισμός II 1

ΣΕΤ ΑΣΚΗΣΕΩΝ 2. Προθεσμία: Τετάρτη 23/11/2016, 21:00

UNIX System Programming

Δείκτες (Pointers) Ένας δείκτης είναι μια μεταβλητή με τιμή μια διεύθυνση μνήμης. 9.8

Κατανεμημένος και Παράλληλος Προγραμματισμός. Εισαγωγή στο MPI. Εγκατάσταση MPICH σε ένα ΗΥ 10/3/2017

Λειτουργικά Συστήματα 7ο εξάμηνο, Ακαδημαϊκή περίοδος

ΕΠΕΞΕΡΓΑΣΙΑ ΑΡΧΕΙΩΝ Λέµε αρχείο

Η-Υ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ. Εργαστήριο 1 Εισαγωγή στη C. Σοφία Μπαλτζή s.mpaltzi@di.uoa.gr

Εθνικό Μετσόβιο Πολυτεχνείο Σχολή Ηλεκτρολόγων Μηχ. και Μηχανικών Υπολογιστών Εργαστήριο Υπολογιστικών Συστημάτων. Συγχρονισμός

Η γλώσσα προγραμματισμού C

Dr. Garmpis Aristogiannis - EPDO TEI Messolonghi

Κεφάλαιο Πίνακες Ι. (Διάλεξη 16)

ΕΙΣΑΓΩΓΗ ΣΤΟΝ ΔΟΜΗΜΕΝΟ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟ

ΕΡΓΑΣΤΗΡΙΟ 8: Πολυδιάστατοι Πίνακες και Δυναμική Δέσμευση Μνήμης

Εθνικό Μετσόβιο Πολυτεχνείο Σχολή Ηλεκτρολόγων Μηχ. και Μηχανικών Υπολογιστών Εργαστήριο Υπολογιστικών Συστημάτων. Συγχρονισμός

Transcript:

Δρ. Βασίλης Ταμπακάς Δρ. Ιωάννης Ε. Λιβιέρης Τμήμα Μηχανικών Πληροφορικής Τ.Ε

Περιεχόμενα Περιεχόμενα... 1 1. Εισαγωγή, Θεωρητική Υποδομή Εργαστηριακής Άσκησης... 2 2. Εργαστηριακή υποδομή εργαστηριακής άσκησης... 2 3. Αμοιβαίος αποκλεισμός... 4 4. Συγχρονισμός Διεργασιών... 7 5. Ασκήσεις... 9 Παράρτημα... 15 1

1. Εισαγωγή, Θεωρητική Υποδομή Εργαστηριακής Άσκησης To αντικείμενο της εργαστηριακής άσκησης είναι η εξοικείωση της χρήσης των σημαφόρων στο λειτουργικό σύστημα LINUX και η υλοποίηση και η εφαρμογή των αρχών του αμοιβαίου αποκλεισμού και του συγχρονισμού στις συντρέχουσες/παράλληλες διεργασίες με τη χρήση των σημαφόρων. Για το σκοπό αυτό οι φοιτητές θα πρέπει να εξοικειωθούν με τις κλήσεις συστήματος του LINUX sem_init(), sem_open( ), sem_close( ), sem_wait( ), sem_post( ), sem_destroy( ), sem_unlink( ), sem_getvalue( ). Επίσης οι φοιτητές πριν πραγματοποιήσουν την εργαστηριακή άσκηση πρέπει να βεβαιωθούν ότι κατέχουν ικανοποιητικά το αντίστοιχο κεφάλαιο θεωρίας (Συγχρονισμός Διεργασιών μέσω Σημαφόρων). Προτείνεται να το μελετήσουν από τα συγγράμματα που διατίθενται για το μάθημα και κυρίως από τις διαφάνειες διαλέξεων της θεωρίας (Κεφάλαιο 4 Συγχρονισμός Διεργασιών σελ. 42-88). 2. Εργαστηριακή υποδομή εργαστηριακής άσκησης Στα συστήματα UNIX/LINUX έχουν επικρατήσει δυο είδη σημαφόρων: Οι σημαφόροι τύπου SystemV και οι σημαφόροι τύπου Posix. Στο SystemV χρησιμοποιούνται 3 συναρτήσεις για τη διαχείριση των σημαφόρων και συγκεκριμένα οι semget( ), semop( ), semctl( ). Με τη semget( ) δημιουργείται ένας περιγραφέας σημαφόρος για να χρησιμοποιηθεί στις υπόλοιπες συναρτήσεις. Με τη συνάρτηση semop( ) εκτελείται μια πράξη UP (signal) ή DOWN (wait) στον αντίστοιχο σημαφόρο. Με τη συνάρτηση semctl( ) ελέγχεται ο σημαφόρος και μπορεί να καταστραφεί. Το POSIX αποτελεί μια οικογένεια προτύπων και είναι μια συντομογραφία του όρου «Φορητή διεπαφή λειτουργικών συστημάτων» (Portable Operating System Interface). Το POSIX προσφέρει ένα σύνολο προτύπων παροχής κριτηρίων συμμόρφωσης για υπηρεσίες λειτουργικών συστημάτων και είναι σχεδιασμένο να επιτρέπει σε προγράμματα εφαρμογών να γράφουν εφαρμογές που μπορούν εύκολα να μεταφέρονται μεταξύ διαφορετικών λειτουργικών συστημάτων. Προσδιορίζει επίσης έναν καθορισμένο τρόπο για μια εφαρμογή να αλληλεπιδρά με το λειτουργικό σύστημα. Πιο συγκεκριμένα, το πρότυπο POSIX standard προσδιορίζει τις διεπαφές για βασικές λειτουργίες, όπως λειτουργίες αρχείων, διαχείριση εργασιών, σήματα και συσκευές. Άλλες μετέπειτα εκδόσεις του POSIX προσδιορίζουν επεκτάσεις πραγματικού χρόνου και πολυνηματισμό (multithreads) με αποτέλεσμα τα συστήματα που είναι συμβατά με το POSIX να χρησιμοποιούνται ευρέως στις εφαρμογές πραγματικού χρόνου. 2

Συνήθως τα σύγχρονα λειτουργικά συστήματα υποστηρίζουν και τους δυο τρόπους σημαφόρων. Οι πιο σημαντικές συναρτήσεις για τους σημαφόρους του POSIX είναι η sem_init(), η sem_wait(), η sem_post() και η sem_destroy(). H sem_init() αρχικοποιεί και δημιουργεί ένα σημαφόρο. Η συνάρτηση sem_wait() εκτελεί μια λειτουργία DOWN (ή wait) στo συγκεκριμένη σημαφόρο. Η συνάρτηση sem_post() εκτελεί μια λειτουργία UP (ή signal) στo συγκεκριμένη σημαφόρο. Τέλος, η συνάρτηση sem_destroy() καταστρέφει τη συγκεκριμένη σημαφόρο. O πίνακας που ακολουθεί παρουσιάζει αναλυτικά τις συναρτήσεις, τα αντίστοιχα ορίσματα και τη λειτουργία των σημαφόρων POSIX. int sem_init(sem_t *sem, int pshared, unsigned int value); Αρχικοποιεί έναν μη ονοματισμένο σημαφόρο int sem_destroy(sem_t *sem); Καταστρέφει έναν μη ονοματισμένο σημαφόρο και απελευθερώνει τους πόρους που κρατάει sem_t *sem_open(const char *name, int oflag,...); int sem_close(sem_t *sem); int sem_unlink(const char *name); int sem_wait(sem_t *sem); int sem_post(sem_t *sem); Αρχικοποιεί και ανοίγει έναν ονοματισμένο σημαφόρο Κλείνει έναν ονοματισμένο σημαφόρο Καταστρέφει έναν ονοματισμένο σημαφόρο Ελαττώνει (κλειδώνει) κατά ένα την τιμή του σημαφόρου. Αν η τιμή του σημαφόρου είναι θετική τότε πραγματοποιείται η μείωση και η συνάρτηση επιστρέφει άμεσα. Αν η τιμή του σημαφόρου είναι μηδέν τότε η συνάρτηση μπλοκάρεται έως να είναι δυνατή η μείωση (π.χ. η τιμή του να γίνει θετική). Αυξάνει (ξεκλειδώνει) κατά ένα την τιμή του σημαφόρου. Αν η τιμή του σημαφόρου γίνει (από 0) θετική τότε μια άλλη διεργασία (ή νήμα) που ήταν μπλοκαρισμένο θα ξυπνήσει για να εκτελέσει το κλείδωμα του σημαφόρου. 3

int sem_getvalue(sem_t *sem, int *sval); Αποθηκεύει την τρέχουσα τιμή του σημαφόρου (sem) στο sval. 3. Αμοιβαίος αποκλεισμός Ο αμοιβαίος αποκλεισμός μεταξύ δυο διεργασιών P και Q επιτυγχάνεται μέσω του παρακάτω σχήματος συγχρονισμού μέσω σημαφόρων: var s : semaphore; begin s :=1; cobegin Process P Process Q repeat wait (s); <κρίσιμη περιοχή> signal (s); forever repeat wait (s); <κρίσιμη περιοχή> signal (s); forever coend; end. Παράδειγμα 1 Να γίνει ένα πρόγραμμα στο οποίο με τη χρήση της κλήσης fork ( ) να δημιουργούνται δυο συντρέχουσες διεργασίες (γονική θυγατρική). Η γονική διεργασία θα πρέπει να τυπώνει το μήνυμα "Parent is in critical section και στη συνέχεια "Parent exits critical section Επίσης η θυγατρική θα πρέπει να τυπώνει το μήνυμα "Child is in critical section και στη συνέχεια "Child exits critical section Θα πρέπει τα μηνύματα των δυο διεργασιών να εκτυπώνονται αδιαίρετα. Προσδιορίστε την κρίσιμη περιοχή και προστατέψτε την με τη χρήση POSIX σημαφόρων ώστε να ικανοποιείται η ανωτέρω απαίτηση. (semaphore1.c) Επίλυση #include <stdio.h> 4

#include <stdlib.h> #include <sys/types.h> #include <semaphore.h> #include <fcntl.h> typedef sem_t Semaphore; void display(char *str); /* semaphores are usually declared global variables */ /* synch semaphore */ Semaphore *mutex; int main() pid_t pid; /* fork pid */ /**********************************************/ /* initialize semaphores for shared processes */ mutex = sem_open ("Sem", O_CREAT O_EXCL, 0644, 1); /* name of semaphore is "Sem", semaphore is */ /* reached using this name */ printf ("Semaphore initialized.\n\n"); /* fork child processes */ pid = fork (); if (pid > 0) sem_wait (mutex); /* DOWN operation */ /* Critical region: START */ printf ("Parent is in critical section.\n"); display("i am the parent...\n"); printf ("Parent exits critical section.\n\n\n"); /* Critical region: END */ sem_post (mutex); /* UP operation */ wait(null); /* unlink prevents the semaphore existing forever */ /* if a crash occurs during the execution */ sem_unlink ("Sem"); sem_close(mutex); 5

else if (pid == 0) sem_wait (mutex); /* DOWN operation */ /* Critical region: START */ printf ("Child is in critical section.\n"); display("hello world...\n"); printf ("Child exits critical section.\n\n\n"); /* Critical region: END */ sem_post (mutex); /* UP operation */ else /* fork failed */ /* check for error */ sem_unlink ("Sem"); sem_close(mutex); printf ("Fork error.\n"); exit (0); void display(char *str) char *p; for (p=str; *p; p++) write(1, p, 1); usleep(100); 6

4. Συγχρονισμός Διεργασιών Ο συγχρονισμός μεταξύ δυο διεργασιών P και Q (με τη λογική πρώτα εκτελείται η P μετά η Q, στη συνέχεια η P, μετά η Q κλπ.) επιτυγχάνεται μέσω του παρακάτω σχήματος συγχρονισμού μέσω σημαφόρων: var s1, s2 : semaphore; begin s1 :=1; s2 :=0; cobegin Process P Process Q repeat wait (s1); Γράψε ΤΙΚ; signal (s2); forever repeat wait (s2); Γράψε ΤΑΚ; signal (s1); forever coend end. Παράδειγμα 2 Να γίνει ένα πρόγραμμα στο οποίο με τη χρήση της κλήσης fork ( ) να δημιουργούνται δυο συντρέχουσες διεργασίες (γονική θυγατρική). Η γονική διεργασία θα πρέπει να τυπώνει το μήνυμα: «Ι am the parent» και η γονική το μήνυμα: «Ι am the child» Θα πρέπει τα μηνύματα των δυο διεργασιών να εκτυπώνονται αυστηρά με τη σειρά δηλαδή πρώτα της γονικής και μετά της θυγατρικής διεργασίας. Υλοποιείστε το συγκεκριμένο σχήμα συγχρονισμού με τη χρήση POSIX σημαφόρων (semaphore2.c) #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <semaphore.h> #include <fcntl.h> typedef sem_t Semaphore; 7

void display(char *str); /* semaphores are usually declared global variables */ /* synch semaphore */ Semaphore *synch; int main() pid_t pid; /* fork pid */ /***************************************************/ /* initialize semaphores for shared processes */ synch = sem_open ("psem", O_CREAT O_EXCL, 0644, 0); /* fork child processes */ pid = fork (); if (pid > 0) sem_wait (synch); /* UP operation */ display("i am the parent\n"); wait(null); /* unlink prevents the semaphore existing forever */ /* if a crash occurs during the execution */ sem_unlink ("psem"); sem_close(synch); else if (pid == 0) display("i am the child\n"); sem_post (synch); /* DOWN operation */ else /* fork failed */ /* unlink prevents the semaphore existing forever */ /* if a crash occurs during the execution */ sem_unlink ("psem"); sem_close(synch); printf ("Fork error.\n"); 8

exit (0); void display(char *str) char *p; for (p=str; *p; p++) write(1, p, 1); usleep(100); 5. Ασκήσεις Άσκηση 1: Υποθέστε δυο συντρέχουσες διεργασίες P και Q από τις οποίες η P δημιουργεί και εκχωρεί στη μεταβλητή S, όλη τη σειρά αριθμών 1..100 και η Q εκτυπώνει την S (δείτε σελίδα 65-66 των διαφανειών του κεφαλαίου 4 - Συγχρονισμός). Με τη χρήση της κλήσης fork( ) και των σημαφόρων POSIX δημιουργείστε τις δυο διεργασίες και συγχρονίστε τις ώστε να εκτυπώνεται όλη η σειρά αριθμών 1..100. Άσκηση 2:Υποθέστε τις παρακάτω συντρέχουσες διεργασίες του LINUX: P1: X1:=5; X2:=15; P2: print(x1); P3: print(x2); P4: X:=X1+X2; P5: print(x); Θεωρείστε πως οι Χ, Χ1, Χ2 είναι διαμοιραζόμενες μεταβλητές. Δημιουργείστε τον κατάλληλο γράφο προτεραιότητας που θα υποδεικνύει το σωστό σχήμα συγχρονισμού των πέντε διεργασιών. Στη συνέχεια χρησιμοποιώντας τη κλήση fork( ) και τους σημαφόρων POSIX δημιουργείστε τις πέντε συντρέχουσες διεργασίες και συγχρονίστε τις ώστε να εκτυπώνεται το σωστό αποτέλεσμα. Άσκηση 3: Να τροποποιήσετε το παρακάτω κώδικα (semaphore_ask1.c) 9

int main (int argc, char **argv) pid_t pid; /* fork child processes */ pid = fork (); if (pid > 0) display ("Good morning "); display ("a nice day\n\n"); wait(null); else if (pid == 0) display ("sir\n"); display ("I wish you, "); else /* fork failed */ printf ("Fork error.\n"); exit (0); Έτσι ώστε να έχετε τη παρακάτω εκτύπωση μηνυμάτων Good morning sir I wish you, a nice day Άσκηση 4: Να τροποποιήσετε το παρακάτω κώδικα (semaphore_ask2.c) #include <stdio.h> #include <stdlib.h> #include <sys/types.h> void display(char *str); int main () int i; /* loop variables */ pid_t pid; /* fork pid */ /* fork child processes */ 10

pid = fork (); if (pid > 0) for (i=0; i<10; i++) display ("ab"); wait(null); else if (pid == 0) for (i=0; i<10; i++) display ("cd\n"); else /* fork failed */ /* check for error */ printf ("Fork error.\n"); exit (0); Έτσι ώστε να έχετε τη παρακάτω εκτύπωση μηνυμάτων Άσκηση 5: Δίνεται ο παρακάτω κώδικας (semaphore_ask3.c), ο οποίος δημιουργεί n-διεργασίες (θυγατρικές) κάθε μία από τις οποίες εκτελεί το παρακάτω κομμάτι κώδικα t = *p; t++; sleep (nseconds[i]); *p = t; Κάθε νέα (θυγατρική) διεργασία περιμένει ένα τυχαίο αριθμό δευτερολέπτων και στη συνέχεια αυξάνει τη κοινά διαμοιραζόμενα μεταβλητή *p. Nα χρησιμοποιήσετε σημαφόρους έτσι ώστε να προστατέψετε τη κρίσιμη περιοχή κάθε διεργασίας για να έχετε το παρακάτω αποτέλεσμα. 11

#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/shm.h> #include <errno.h> #include <semaphore.h> #include <fcntl.h> int main () int i; /* loop variables */ int t; /* temporary variable */ key_t shmkey; /* shared memory key */ int shmid; /* shared memory id */ pid_t pid; /* fork pid */ int *p; /* shared variable */ unsigned int n; /* fork count */ unsigned int value; /* semaphore value */ int *nseconds; /* Dynamic array */ /* stores the number of secs */ /* the i-process waits */ /* Initializes random number generator */ srand(time(null)); /*****************************************************/ /* Initialize a shared variable in shared memory */ /* valid directory name and a number */ shmkey = ftok ("/dev/null", 5); shmid = shmget(shmkey, sizeof (int),0644 IPC_CREAT); /* shared memory error check */ if (shmid < 0) perror ("shmget\n"); exit (1); /*****************************************************/ 12

/*****************************************************/ /* attach p to shared memory */ p = (int *) shmat (shmid, NULL, 0); *p = 0; /*****************************************************/ printf ("How many children do you want to fork?\n"); printf ("Fork count: "); scanf ("%u", &n); /*****************************************************/ /* Dynamic array which stores the number of secs */ /* the i-process will wait */ nseconds = (int *)malloc(n * sizeof(int)); for (i=0; i<n; i++) nseconds[i] = rand()%4 + 1; /*****************************************************/ /* fork child processes */ for (i = 0; i < n; i++) pid = fork (); if (pid < 0) printf ("Fork error.\n"); else if (pid == 0) /* child processes */ break; /******************************************************/ /****************** PARENT PROCESS ****************/ /******************************************************/ if (pid > 0) /* wait for all children to exit */ while (pid = waitpid (-1, NULL, 0)) if (errno == ECHILD) break; 13

printf (" Parent: All children have exited.\n"); printf (" *p = %d\n\n\n", *p); /* shared memory detach */ shmdt (p); shmctl (shmid, IPC_RMID, 0); /******************************************************/ /****************** CHILD PROCESS *****************/ /******************************************************/ else printf (" Child(%d) enters the critical section.\n", i+1); printf (" Waiting %d seconds.\n", nseconds[i]); t = *p; t++; sleep (nseconds[i]); *p = t; printf (" Increasing *p\n"); printf (" Child(%d) exits the critical region\n", i); printf (" new value of *p=%d.\n\n\n", *p); exit (0); 14

Παράρτημα Υποδείξεις: Ο πηγαίος κώδικας από όλα τα παραδείγματα που χρησιμοποιούνται σε αυτό το κείμενο βρίσκεται στο φάκελο Έγγραφα\Source Code, στο δικτυακό τόπο του μαθήματος στο eclass. Η μεταγλώττιση ενός προγράμματος στο Linux γίνεται με τη χρήση της εντολής: gcc -pthread o <όνομα εκτελέσιμου> <όνομα αρχείου που περιέχει τον πηγαίο κώδικα>. Η εντολή αυτή θα πρέπει να δοθεί από τερματικό ενώ ο τρέχων κατάλογος εργασίας θα πρέπει να είναι αυτός στον οποίο βρίσκεται αποθηκευμένος ο πηγαίος κώδικας του προγράμματος. (Η εντολή με την οποία μπορούμε να βρούμε τον τρέχοντα κατάλογο είναι η pwd ενώ μετακινούμαστε μεταξύ καταλόγων με την εντολή cd. Τα περιεχόμενα των καταλόγων βρίσκονται με την εντολή ls. Περισσότερες πληροφορίες για τη λειτουργικότητα και τις παραμέτρους των εντολών (αλλά και των κλήσεων συστήματος) μπορούν να βρεθούν μέσω της βοήθειας του Linux που δίνεται αν πληκτρολογήσουμε man <όνομα εντολής>. Η εκτέλεση ενός προγράμματος γίνεται πληκτρολογώντας:./<όνομα εκτελέσιμου> Η εκτέλεση ενός προγράμματος στο παρασκήνιο γίνεται πληκτρολογώντας:./<όνομα εκτελέσιμου> & 15