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

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

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

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

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

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

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

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

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

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

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

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

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

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

UNIX System Programming

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

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

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

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

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

Διαχείριση Διεργασιών και Διαδιεργασιακή Επικοινωνία

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

Δίκτυα Επικοινωνιών ΙΙ: Network Programming UDP Sockets, Signals

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

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

Διάλεξη 14: Διεργασίες: Έλεγχος & Σήματα (Processes: Control & Signals)

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

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

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

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

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

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

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

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

Διαχείριση Διεργασιών και Διαδιεργασιακή Επικοινωνία

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

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

Δομημένος Προγραμματισμός

Μερικές άλλες χρήσιμες εντολές

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

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

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

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

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

ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ ΔΙΕΡΓΑΣΙΕΣ

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

Unix: Εντολές, οργάνωση και χειρισµός αρχείων, διεργασίες

Ανάπτυξη και Σχεδίαση Λογισμικού

Εισαγωγή στο περιβάλλον προγραμματισμού του εργαστηρίου. Λειτουργικά Συστήματα Εργαστήριο Υπολογιστικών Συστημάτων ΕΜΠ

Εργαστήριο Λειτουργικών Συστημάτων Ακ. Έτος Άσκηση 4. Πλήθος οπών <tab> Μέσο μέγεθος σε mb

Εισαγωγή στο περιβάλλον προγραμματισμού του εργαστηρίου

1. Εισαγωγή. Λειτουργικά Συστήματα Η/Υ. Διεργασίες. Ορισμός ΚΕΦΑΛΑΙΟ 3 - ΔΙΕΡΓΑΣΙΕΣ. Κεφάλαιο 3 «Διεργασίες»

Εισαγωγή στην Πληροφορική

ΙΩΑΝΝΗΣ ΚΩΝΣΤΑΝΤΙΝΟΥ 2ο ΦΡΟΝΤΙΣΤΗΡΙΟ ΠΑΡΑΣΚΕΥΗ 26 ΟΚΤΩΒΡΙΟΥ 2012 ΑΙΘΟΥΣΑ Β4

Αγωγοί/Σωλήνες (Pipes) Προγραμματισμός II 1

Τµήµα Ηλεκτρολόγων Μηχανικών & Μηχανικών Υπολογιστών Σεπτέµβριος 2013

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

Παρακάτω δίνεται o σκελετός προγράμματος σε γλώσσα C. Σχολιάστε κάθε γραμμή του κώδικα.

είκτες και Πίνακες (2)

Εισαγωγή στον Προγραμματισμό Εργαστήριο 3: Βοηθητικά προγράμματα του Linux CLI. Οκτώβριος 2014 Χ. Αλεξανδράκη Γ. Δημητρακάκης

ΕΡΓΑΣΤΗΡΙΟ 9: Συμβολοσειρές και Ορίσματα Γραμμής Εντολής

ΕΡΓΑΣΤΗΡΙΟ 9: Συμβολοσειρές και Ορίσματα Γραμμής Εντολής

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

Διαδικασία Ανάπτυξης Λογισμικού

$./jms console -w <jms in> -r <jms out> -o <operations file> namedpipe. (standard input).

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

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

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

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

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

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

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

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

Μερικές άλλες χρήσιμες εντολές

waitpid(), read(), write(), pipe(), mkfifo() κ.α.).

Εισαγωγή στον Προγραμματισμό Εργαστήριο 3: Βοηθητικά προγράμματα του Linux CLI. Οκτώβριος 2014 Χ. Αλεξανδράκη Γ. Δημητρακάκης

Χρονοδρομολογητής Κυκλικής Επαναφοράς

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

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

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

ΕΝΤΟΛΕΣ ΕΠΑΝΑΛΗΨΗΣ. for (παράσταση_1; παράσταση_2; παράσταση_3) εντολή επόμενη εντολή

Σε γενικές γραμμές, είναι καλή πρακτική να γράϕουμε προγράμματα C που αποτελούνται από πολλές και μικρές συναρτήσεις, παρά από λίγες και μεγάλες.

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

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

ΑΡΧΕΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ

Topic 4: Processes. *Ευχαριστίες στους Τάκη Σταµατόπουλο, Αλέξη ελή, και Αντώνη ελιγιαννάκη

#include <stdlib.h> Α. [-128,127] Β. [-127,128] Γ. [-128,128]

Προγραμματισμός Ι (ΗΥ120)

Εργαστήριο ΤΟ ΛΕΙΤΟΥΡΓΙΚΟ ΣΥΣΤΗΜΑ UNIX

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

Υπολογισμός - Εντολές Επανάληψης

Λειτουργικά. Συστήματα Ι. Φ ρ ο ν τ ι σ τ ή ρ ι ο. Αριστείδης Ηλίας. Εργαστήριο Ηλεκτρονικών Υπολογιστών

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

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΥΠΟΛΟΓΙΣΤΩΝ & ΥΠΟΛΟΓΙΣΤΙΚΗ ΦΥΣΙΚΗ

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

Διάλεξη 5η: Εντολές Επανάληψης

ΕΡΓΑΣΤΗΡΙΟ 6: Συναρτήσεις και Αναδρομή

Αλγόριθμοι Ταξινόμησης Μέρος 1

ΕΡΓΑΣΤΗΡΙΟ 1 ΕΙΣΑΓΩΓΗ ΣΤΗ C. Τµήµα Πληροφορικής και Τηλεπικοινωνιών

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

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

Transcript:

Πανεπιστήμιο Θεσσαλίας Τμήμα Πληροφορικής ΕΥ311-Διαδικτυακός και Ταυτόχρονος Προγραμματισμός Εργαστήριο: Παραδείγματα δημιουργίας διεργασιών στο Linux Ένα πρόγραμμα (το στιγμιότυπο της εκτέλεσης του οποίου αποτελεί μια διεργασία) μπορεί να δημιουργήσει διεργασίες-παιδιά (ή θυγατρικές διεργασίες) χρησιμοποιώντας την κλήση συστήματος fork(). pid_t fork(void); Επιτυχής εκτέλεση της fork() επιστρέφει το process id της διεργασίας παιδί που δημιουργήθηκε στην πατρική διεργασία και 0 στη διεργασία παιδί. Παράδειγμα 1 Στον κώδικα που ακολουθεί βρίσκεται ένα απλό παράδειγμα δημιουργίας διεργασιών. Εκτελέστε το και παρατηρείστε ότι παρότι η printf() καλείται μια φορά, η έξοδος εμφανίζεται δύο φορές (μια για τον πατέρα και μια για το παιδί). pid_t p; /* fork returns type pid_t */ p = fork(); printf("fork returned %d\n", p); Η διεργασία παιδί είναι μια νέα διεργασία, με δικό της process id, της οποίας ο κώδικας και οι πόροι που διαθέτει αποτελούν αντίγραφο της διεργασίας που τη δημιούργησε. Η εκτέλεση στη διεργασία παιδί, θα ξεκινήσει από το σημείο του κώδικα της πατρικής διεργασίας που κλήθηκε η fork(). Παράδειγμα 2 Στη συνέχεια, σε ένα πιο προχωρημένο παράδειγμα, η τιμή που επιστρέφεται από τη fork() ελέγχεται και ανάλογα με τον αν εκτελείται ο κώδικας της πατρικής ή της θυγατρικής διεργασίας εμφανίζονται τα process ids της αρχικής και της θυγατρικής διεργασίας με τη χρήση των κατάλληλων, κατά περίπτωση, κλήσεων συστήματος: pid_t getpid(void); pid_t getppid(void); 1

Η κλήση συστήματος getpid() επιστρέφει το process id της διεργασίας που την καλεί και η κλήση συστήματος getppid() επιστρέφει, στη διεργασία που την καλεί, το process id της πατρικής της διεργασίας. pid_t p; printf("original program, pid=%d\n", getpid()); p = fork(); if (p == 0) { printf("in child process, pid=%d, ppid=%d\n", getpid(), getppid()); else { printf("in parent, pid=%d, fork returned=%d\n", getpid(), p); Παράδειγμα 3 Στο ακόλουθο παράδειγμα δείτε πως αντικαθιστούμε τον κώδικα που θα εκτελέσει η θυγατρική διεργασία με την κλήση συστήματος execv(). //Δηλώσεις της οικογένειας κλήσεων συστήματος exec extern char **environ; int execl(const char *path, const char *arg,...); int execlp(const char *file, const char *arg,...); int execle(const char *path, const char *arg,..., char * const envp[]); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); run /* Define a null terminated array of the command to followed by any parameters, in this case none */ char *arg[] = { "/bin/ls", 0 ; /* fork, and exec within child process */ if (fork() == 0) { printf("in child process:\n"); execv(arg[0], arg); printf("i will never be called\n"); printf("execution continues in parent process\n"); 2

Παράδειγμα 4 Στο επόμενο παράδειγμα ο πατέρας περιμένει την ολοκλήρωση της εκτέλεσης του παιδιού με την κλήση συστήματος waitpid(). Οι κλήσεις συστήματος wait() και waitpid() αναστέλλουν τη λειτουργία της διεργασίας που τις καλεί έως ότου α) μια από τις διεργασίες παιδιά που έχουν δημιουργηθεί επιστρέψει (κλήση συστήματος wait() ή β) η διεργασία που προσδιορίζεται από το όρισμα pid της waitpid() επιστρέψει. Οι κλήσεις συστήματος wait() και waitpid() λαμβάνουν στη μεταβλητή status την κατάσταση που επέστρεψε (μέσω της return ή της exit()) η διεργασία παιδί. Την κατάσταση αυτή μπορούν να εμφανίζουν ως ακέραιο με τη μακροεντολή WEXITSTATUS (για περισσότερες πληροφορίες ανατρέξτε στο εγχειρίδιο του συστήματος). #include <sys/wait.h> pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int options); run /* Define a null terminated array of the command to followed by any parameters, in this case none */ char *arg[] = { "/bin/pwd", 0 ; pid_t pid; int status; /* fork, and exec within child process */ if ((pid=fork()) == 0) { printf("in child process:\n"); sleep(30); execv(arg[0], arg); printf("i will never be called\n"); else if (pid<0) { //fork failed perror("fork"); status = -1; else { printf("execution continues in parent process\n"); if (waitpid (pid, &status, 0)!= pid) status = -1; return status; 3

Παράδειγμα 5 Στο επόμενο παράδειγμα η γονική διεργασία τερματίζει πριν τη διεργασία παιδί. Η διεργασία παιδί που έχει δημιουργηθεί, κληρονομείται από την αρχική διεργασία (init) του λειτουργικού συστήματος Linux με process id 1. Στο παρακάτω παράδειγμα, η πατρική διεργασία καλεί τη fork(), περιμένει δύο δευτερόλεπτα (καλώντας τη sleep(2)) και στη συνέχεια τερματίζει. H διεργασία παιδί συνεχίζει εμφανίζοντας το process id της γονικής της διεργασίας για 5 δευτερόλεπτα. Παρατηρείστε ότι το ppid της διεργασίας αλλάζει σε 1 μετά τον τερματισμό της πατρικής διεργασίας (μετά την ολοκλήρωση της πατρικής διεργασίας ο έλεγχος επιστρέφει στο κέλυφος του λειτουργικού συστήματος αφού το παιδί εκτελείται στο παρασκήνιο). int main(void) { int i; if (fork()) { /* Parent */ sleep(2); _exit(0); for (i=0; i < 5; i++) { printf("my parent is %d\n", getppid()); sleep(1); Παράδειγμα 6 Το παράδειγμα 6 δείχνει το αντίθετο από το παράδειγμα 5, δηλαδή τι συμβαίνει όταν η διεργασία παιδί τερματίζει πριν τη γονική διεργασία. int main(void) { int i; if (!fork()) { /* Child exits immediately*/ _exit(0); /* Parent waits around for a minute */ sleep(60); Εκτελέστε το πρόγραμμα στο παρασκήνιο (χρησιμοποιώντας τον τελεστή &). Εμφανίστε μια λίστα των διεργασιών του συστήματος (με την εντολή ps ef grep <αριθμός διεργασίας που επιστράφηκε με την εκτέλεση του προγράμματος>). Η διεργασία παιδί, παρότι τερματίστηκε, εμφανίζεται στο σύστημα 4

ως defunct ή αλλιώς ως zombie. Όταν η γονική διεργασία ολοκληρώσει, 60 δευτερόλεπτα αργότερα, και οι δύο διεργασίες εξαφανίζονται. Είναι απαραίτητο η γονική διεργασία να φροντίζει για την ολοκλήρωση της εκτέλεσης των θυγατρικών της διεργασιών και να μην αφήνει διεργασίες παιδιά σε κατάσταση defunct. Το γεγονός αυτό μπορεί να είναι ιδιαίτερα επιβλαβές για τους πόρους του συστήματος σε περίπτωση εκτέλεσης προγραμμάτων εξυπηρετητών που προγραμματίζονται να μην τερματίζουν από μόνοι τους ποτέ (μπορεί φυσικά να τους τερματίσει ο διαχειριστής του συστήματος). Διεργασίες παιδιά εξυπηρετητών που γίνονται defunct κρατούν δεσμευμένους πόρους και δεν τερματίζονται ποτέ. Παράδειγμα 7 Δείτε τι συμβαίνει στα ανοικτά αρχεία μιας διεργασίας, εκτελώντας τον κώδικα που ακολουθεί. Θα πρέπει να δημιουργήσετε ένα αρχείο με όνομα infile στον κατάλογο τον οποίο βρίσκεται και ο πηγαίος κώδικας του προγράμματος. Το αρχείο αυτό θα περιέχει έναν αριθμό από το 1 έως το 10 σε κάθε γραμμή. #include <strings.h> #include <sys/stat.h> #include <fcntl.h> int main(void) { int fd_in, fd_out; char buf[1024]; memset(buf, 0, 1024); /* clear buffer*/ fd_in = open("/tmp/infile", O_RDONLY); fd_out = open("/tmp/outfile", O_WRONLY O_CREAT); fork(); /* It doesn't matter about child vs parent */ while (read(fd_in, buf, 2) > 0) { /* Loop through the infile */ printf("%d: %s", getpid(), buf); /* Write a line */ sprintf(buf, "%d Hello, world!\n\r", getpid()); write(fd_out, buf, strlen(buf)); sleep(1); memset(buf, 0, 1024); /* clear buffer*/ sleep(10); Όταν δημιουργούνται διεργασίες παιδιά ο πυρήνας του λειτουργικού συστήματος δημιουργεί ένα αντίγραφο όλων των ανοιχτών περιγραφέων αρχείου (file descriptors). Τα ερωτήματα που δημιουργούνται εδώ είναι: αν έχει ανοιχτεί ένα αρχείο πριν την κλήση της fork() τι συμβαίνει όταν και οι δύο διεργασίες επιχειρήσουν ανάγνωση ή εγγραφή; Υπάρχει περίπτωση μια διεργασία να γράψει δεδομένα πάνω σε αυτά της άλλης; Υπάρχει περίπτωση να διαβαστούν δύο αντίγραφα του ίδιου μέρους των περιεχομένων του αρχείου; 5

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