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

Σχετικά έγγραφα
Διαχείριση Διεργασιών και Διαδιεργασιακή Επικοινωνία

UNIX System Programming

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

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

Διεργασίες και Νήματα (1/2)

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

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

Διεργασίες - Σύνοψη. Διακοπές, προνομιούχος κατάσταση Κλήσεις συστήματος. Ορισμός, μεταβάσεις κατάστασης κύκλος ζωής

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

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

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

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

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

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

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

Προγραμματισμός συστημάτων UNIX/POSIX. Σήματα (signals)

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

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

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

Σήματα (Signals) Προγραμματισμός II 1

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

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

Σήματα (Signals) Προγραμματισμός II 1

Σήματα (Signals) Προγραμματισμός II 1

Εζληθό Μεηζόβην Πνιπηερλείν Σρνιή Ηιεθηξνιόγσλ Μερ. θαη Μεραληθώλ Υπνινγηζηώλ Εξγαζηήξην Υπνινγηζηηθώλ Σπζηεκάησλ.

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

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

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

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

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

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

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

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

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

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

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

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

4 η ιάλεξη: Signals UDP Sockets

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

Διεργασίες και Νήματα (2/2)

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

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

Κεφάλαιο 11 Διαχείριση Διεργασιών

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

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

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

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

make Προγραμματισμός II 1

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

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

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

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

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

Προγραμματισμός Διαχείρισης Συστημάτων ΙΙ

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

Δείκτες σε συναρτήσεις. Προγραμματισμός II 1

Παράδειγµα χρήσης perror, errno (πρόγραµµα errors_demo.c)

Α Β Γ static; printf("%c\n", putchar( A +1)+2); B DB BD. int i = 0; while (++i); printf("*");

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

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

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

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

Εικονική Μνήμη (1/2)

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

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

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

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

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

ΕΝΟΤΗΤΑ 4 Λήψη Αποφάσεων και Συναρτήσεις Ελέγχου

Ανάπτυξη Μεγάλων Εφαρµογών στη Γλώσσα C (2)

Εργαστήριο 5 Αναδρομική διεργασία εισαγωγής καινούριου κόμβου σε ΔΔΑ με αλφαβητική σειρά

Σημειώσεις όγδοης εβδομάδας

Εργαστήριο 8: Αναδρομική διεργασία εισαγωγής καινούριου κόμβου σε ΔΔΑ

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

Πρότυπη Εργαστηριακή Άσκηση

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

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

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

Λειτουργικά Συστήματα. Ενότητα # 10: Προγραμματισμός UNIX Διδάσκων: Γεώργιος Ξυλωμένος Τμήμα: Πληροφορικής

Το λειτουργικό σύστημα. Προγραμματισμός II 1

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

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

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

Ιδιοκτησία Αντικειµένου

File Management και I/O στο UNIX

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

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

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

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

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

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

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

Εγχειρίδιο Συναρτήσεων. Socket *sopen(const int type, const int protocol, const char *host, const char *service)

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

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

Διδάσκων: Κωνσταντίνος Κώστα

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

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

υναµικές οµές εδοµένων (συν.) Στην ενότητα αυτή θα µελετηθούν τα εξής επιµέρους θέµατα:

Περιεχόμενα. Πρόλογος... 21

Transcript:

Εθνικό Μετσόβιο Πολυτεχνείο Σχολή Ηλεκτρολόγων Μηχ. και Μηχανικών Υπολογιστών Εργαστήριο Υπολογιστικών Συστημάτων 2 η Εργαστηριακή Άσκηση: Διαχείριση Διεργασιών και Διαδιεργασιακή Επικοινωνία Λειτουργικά Συστήματα Υπολογιστών 7ο Εξάμηνο, 2017-2018

2 η άσκηση Σύνοψη Διαχείριση διεργασιών Δημιουργία δεδομένου δέντρου διεργασιών με fork() / wait() Δημιουργία αυθαίρετου δέντρου διεργασιών με βάση αρχείο εισόδου που το περιγράφει Διαδιεργασιακή επικοινωνία με σήματα, SIGSTOP / SIGCONT με σωληνώσεις (UNIX pipes)

Θεωρία - Μηχανισμοί Χρήση του make, Makefile Διαχείριση διεργασιών στο UNIX fork(), wait(), waitpid(), explain_wait_status() Σήματα στο UNIX kill(), signal(), sigaction(), race conditions Χειρισμός του σήματος SIGCHLD Ασύγχρονη ειδοποίηση γονικής διεργασίας non-blocking waitpid() Διαδιεργασιακή επικοινωνία με UNIX pipes

Makefile $ cat Makefile # a simple Makefile CC = gcc CFLAGS = -Wall -O2 all: fork-example fork-example: fork-example.o proc-common.o $(CC) -o fork-example fork-example.o proc-common.o proc-common.o: proc-common.c proc-common.h $(CC) $(CFLAGS) -o proc-common.o -c proc-common.c fork-example.o: fork-example.c proc-common.h $(CC) $(CFLAGS) -o fork-example.o -c fork-example.c clean: rm -f fork-example proc-common.o fork-example.o

Makefile $ cat Makefile # a simple Makefile CC = gcc CFLAGS = -Wall -O2 all: fork-example fork-example: fork-example.o proc-common.o $(CC) -o fork-example fork-example.o proc-common.o <Tab> proc-common.o: proc-common.c proc-common.h $(CC) $(CFLAGS) -o proc-common.o -c proc-common.c <Tab> fork-example.o: fork-example.c proc-common.h $(CC) $(CFLAGS) -o fork-example.o -c fork-example.c <Tab> clean: <Tab> rm -f fork-example proc-common.o fork-example.o

Makefile $ cat Makefile # a simple Makefile CC = gcc CFLAGS = -Wall -O2 all: fork-example fork-example: fork-example.o proc-common.o $(CC) -o fork-example fork-example.o proc-common.o <Tab> proc-common.o: proc-common.c proc-common.h $(CC) $(CFLAGS) -o proc-common.o -c proc-common.c <Tab> fork-example.o: fork-example.c proc-common.h $(CC) $(CFLAGS) -o fork-example.o -c fork-example.c <Tab> clean: <Tab> rm -f fork-example proc-common.o fork-example.o $ make gcc -Wall -O2 -o fork-example.o -c fork-example.c gcc -Wall -O2 -o proc-common.o -c proc-common.c gcc -o fork-example fork-example.o proc-common.o

2 η άσκηση Σύνοψη Διαχείριση διεργασιών Δημιουργία δεδομένου δέντρου διεργασιών με fork() / wait() Δημιουργία αυθαίρετου δέντρου διεργασιών με βάση αρχείο εισόδου που το περιγράφει Διαδιεργασιακή επικοινωνία με σήματα, SIGSTOP / SIGCONT με σωληνώσεις (UNIX pipes)

Δέντρο διεργασιών A B E C F D

Δημιουργία στο μοντέλο του UNIX: Δεδομένα : p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 fork()

Δημιουργία στο μοντέλο του UNIX: Δεδομένα : p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 fork()

Δημιουργία στο μοντέλο του UNIX: Δεδομένα : p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 fork()

Δημιουργία στο μοντέλο του UNIX: Δεδομένα : -1 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = -1, errno if (p < 0) { = ENOMEM perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 fork()

Δημιουργία στο μοντέλο του UNIX: Δεδομένα : -1 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = -1, errno if (p < 0) { = ENOMEM perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 fork()

Δημιουργία στο μοντέλο του UNIX: Δεδομένα : -1 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = -1, errno if (p < 0) { = ENOMEM perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 fork()

Δημιουργία στο μοντέλο του UNIX: Δεδομένα : -1 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = -1, errno if (p < 0) { = ENOMEM perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 fork()

Δημιουργία στο μοντέλο του UNIX: fork()

Δημιουργία στο μοντέλο του UNIX: Δεδομένα : p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 fork()

Δημιουργία στο μοντέλο του UNIX: Δεδομένα : p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 fork()

Δημιουργία στο μοντέλο του UNIX: fork() Δεδομένα : p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 Δεδομένα : p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=987

Δημιουργία στο μοντέλο του UNIX: fork() Δεδομένα : 987 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = 987 if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 Δεδομένα : 0 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = 0 if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=987

Δημιουργία στο μοντέλο του UNIX: fork() Δεδομένα : 987 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = 987 if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 Δεδομένα : 0 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = 0 if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=987

Δημιουργία στο μοντέλο του UNIX: fork() Δεδομένα : 987 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = 987 if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 Δεδομένα : 0 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = 0 if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=987

Δημιουργία στο μοντέλο του UNIX: fork() Δεδομένα : 987 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = 987 if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 Δεδομένα : 0 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = 0 if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=987

Δημιουργία στο μοντέλο του UNIX: fork() Δεδομένα : 987 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = 987 if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 Δεδομένα : 0 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = 0 if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=987 987

Δημιουργία στο μοντέλο του UNIX: fork() Δεδομένα : 987 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = 987 if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 Δεδομένα : 0 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = 0 if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=987 987

Δημιουργία στο μοντέλο του UNIX: fork() Δεδομένα : 987 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = 987 if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=981 Δεδομένα : 0 p =? mypid =? Κείμενο: pid_t p, mypid; p = fork(); p = 0 if (p < 0) { perror( fork ); exit(1); else if (p == 0) { mypid = getpid(); child(); else { father(); PID=987 987

Δημιουργία στο μοντέλο του UNIX: fork() Όλες οι διεργασίες προκύπτουν με fork() [σχεδόν όλες] Ίδιο πρόγραμμα με γονική διεργασία, αντίγραφο χώρου μνήμης, κληρονομεί ανοιχτά αρχεία, συνδέσεις, δικαιώματα πρόσβασης Αντικατάσταση προγράμματος διεργασίας: execve() Η γονική διεργασία ενημερώνεται για το θάνατο του παιδιού με wait() συλλογή τιμής τερματισμού (exit status) Μέχρι τότε, παιδί που έχει καλέσει την exit() είναι zombie Αν ο γονέας πεθάνει πρώτα, η διεργασία γίνεται παιδί της init (PID = 1), που κάνει συνεχώς wait() prog-a 981 fork Prog-A 981 wait Prog-A 987 execve Prog-B 987 Prog-B 987 (zombie) exit

wait() / waitpid() Για κάθε fork() πρέπει να γίνει ένα wait() wait(&status) Μπλοκάρει έως οποιοδήποτε παιδί πεθάνει Το status κωδικοποιεί πώς πέθανε η διεργασία Κανονικά (exit()), λόγω κάποιου σήματος (SIGTERM, SIGKILL) Χρήσιμες μακροεντολές για την ερμηνεία του status WIFEXITED(), WEXITSTATUS(), WIFSIGNALED(), WTERMSIG() σας δίνεται η explain_wait_status() Μια πιο ευέλικτη wait(): waitpid() Περιμένει για αλλαγή κατάστασης συγκεκριμένου ή οποιουδήποτε PID διεργασίας-παιδιού Συμπεριφορά ελεγχόμενη από flags (WNOHANG, WUNTRACED)

explain_wait_status() void explain_wait_status(pid_t pid, int status) { if (WIFEXITED(status)) fprintf(stderr, "Child with PID = %ld terminated normally, exit status = %d\n", (long)pid, WEXITSTATUS(status)); else if (WIFSIGNALED(status)) fprintf(stderr, "Child with PID = %ld was terminated by a signal, signo = %d\n", (long)pid, WTERMSIG(status)); else if (WIFSTOPPED(status)) fprintf(stderr, "Child with PID = %ld has been stopped by a signal, signo = %d\n", (long)pid, WSTOPSIG(status)); else { fprintf(stderr, "%s: Internal error: Unhandled case, PID = %ld, status = %d\n", func, (long)pid, status); exit(1); fflush(stderr);

explain_wait_status() void explain_wait_status(pid_t pid, int status) { if (WIFEXITED(status)) fprintf(stderr, "Child with PID = %ld terminated normally, exit status = %d\n", (long)pid, WEXITSTATUS(status)); else if (WIFSIGNALED(status)) fprintf(stderr, "Child with PID = %ld was terminated by a signal, signo = %d\n", (long)pid, WTERMSIG(status)); else if (WIFSTOPPED(status)) fprintf(stderr, "Child with PID = %ld has been stopped by a signal, signo = %d\n", (long)pid, WSTOPSIG(status)); else { fprintf(stderr, "%s: Internal error: Unhandled case, PID = %ld, status = %d\n", func, (long)pid, status); exit(1); fflush(stderr); Παράδειγμα: pid = wait(&status); explain_wait_status(pid, status); if (WIFEXITED(status) WIFSIGNALED(status)) --processes_alive;

Κώδικας: παράδειγμα fork() / wait() void child(void) { compute(10000); exit(7); int main(void) { pid_t p; int status; p = fork(); if (p < 0) { perror("fork"); exit(1); if (p == 0) { child(); exit(1); p = wait(&status); explain_wait_status(p, status); return 0;

Κώδικας: παράδειγμα fork() / wait() void child(void) { compute(10000); exit(7); int main(void) { pid_t p; int status; father p = fork(); if (p < 0) { perror("fork"); exit(1); if (p == 0) { child(); exit(1); child p = wait(&status); explain_wait_status(p, status); return 0;

2 η άσκηση Σύνοψη Διαχείριση διεργασιών Δημιουργία δεδομένου δέντρου διεργασιών με fork() / wait() Δημιουργία αυθαίρετου δέντρου διεργασιών με βάση αρχείο εισόδου που το περιγράφει Διαδιεργασιακή επικοινωνία με σήματα, SIGSTOP / SIGCONT με σωληνώσεις (UNIX pipes)

Βοηθητικές συναρτήσεις - παραδείγματα proc-common.{h,c, fork-example.c, pstree-this.c change_pname() αλλαγή ονόματος διεργασίας explain_wait_status() διαγνωστικό μήνυμα για status της wait() wait_for_ready_children() αναμονή αναστολής παιδιών με SIGSTOP tree.{h,c και tree-example.c get_tree_from_file() ανάγνωση δέντρου από αρχείο, επιστροφή struct tree_node print_tree()

Η δομή struct tree node struct tree_node { unsigned nr_children; char name[node_name_size]; struct tree_node *children; ; A B E C F D

Η δομή struct tree node struct tree_node { unsigned nr_children; char name[node_name_size]; struct tree_node *children; ; 3 Α 1 Β 0 E 1 A B E C C F 0 D 0 F D

int *ip; Αριθμητική με δείκτες

Αριθμητική με δείκτες int *ip; ip

Αριθμητική με δείκτες *ip int *ip; ip

Αριθμητική με δείκτες *ip int *ip; ip ip+1

Αριθμητική με δείκτες *ip *(ip+1) int *ip; ip ip+1

Αριθμητική με δείκτες *ip *(ip+1) *(ip+2) int *ip; ip ip+1 ip+2

Αριθμητική με δείκτες *ip *(ip+1) *(ip+2) *(ip+3) int *ip; ip ip+1 ip+2 ip+3

Αριθμητική με δείκτες ip[0] ip[1] ip[2] ip[3] *ip *(ip+1) *(ip+2) *(ip+3) int *ip; ip ip+1 ip+2 ip+3

Αριθμητική με δείκτες ip[0] ip[1] ip[2] ip[3] *ip *(ip+1) *(ip+2) *(ip+3) int *ip; ip ip+1 ip+2 ip+3 double *dp; dp

Αριθμητική με δείκτες ip[0] ip[1] ip[2] ip[3] *ip *(ip+1) *(ip+2) *(ip+3) int *ip; ip ip+1 ip+2 ip+3 *dp double *dp; dp

Αριθμητική με δείκτες ip[0] ip[1] ip[2] ip[3] *ip *(ip+1) *(ip+2) *(ip+3) int *ip; ip ip+1 ip+2 ip+3 *dp *(dp+1) double *dp; dp dp+1

Αριθμητική με δείκτες ip[0] ip[1] ip[2] ip[3] *ip *(ip+1) *(ip+2) *(ip+3) int *ip; ip ip+1 ip+2 ip+3 dp[0] *dp dp[1] *(dp+1) double *dp; dp dp+1

Η δομή struct tree node struct tree_node { unsigned nr_children; char name[node_name_size]; struct tree_node *children; ; 3 Α 1 Β 0 E 1 A B E C C F 0 D 0 F D

Η δομή struct tree node struct tree_node { unsigned nr_children; char name[node_name_size]; struct tree_node *children; ; t 3 1 0 Α Β E A B E t children 1 C C F 0 D 0 F D

Η δομή struct tree node struct tree_node { unsigned nr_children; char name[node_name_size]; struct tree_node *children; ; t 3 1 0 Α Β E A B E t children 1 C C F 0 D 0 F D

Η δομή struct tree node struct tree_node { unsigned nr_children; char name[node_name_size]; struct tree_node *children; ; t 3 1 0 Α Β E A B E t children t children +1 1 C C F 0 D 0 F D

Η δομή struct tree node struct tree_node { unsigned nr_children; char name[node_name_size]; struct tree_node *children; ; t 3 1 0 Α Β E A B E t children t children +1 1 C C F 0 D 0 F D

Η δομή struct tree node struct tree_node { unsigned nr_children; char name[node_name_size]; struct tree_node *children; ; t 3 1 0 Α Β E A B E t children t children +1 1 C C F t children +2 0 D 0 F D

Αναδρομική διάσχιση: print_tree() static void print_tree(struct tree_node *root, int level) { int i; for (i=0; i<level; i++) printf("\t"); printf("%s\n", root->name); for (i=0; i < root->nr_children; i++){ print_tree(root->children + i, level + 1); A B E void print_tree(struct tree_node *root) { print_tree(root, 0); C F D

Αναδρομική διάσχιση: print_tree() static void print_tree(struct tree_node *root, int level) { int i; for (i=0; i<level; i++) printf("\t"); printf("%s\n", root->name); for (i=0; i < root->nr_children; i++){ print_tree(root->children + i, level + 1); A B E void print_tree(struct tree_node *root) { print_tree(root, 0); C F D

Αναδρομική διάσχιση: print_tree() static void print_tree(struct tree_node *root, int level) { int i; for (i=0; i<level; i++) printf("\t"); printf("%s\n", root->name); for (i=0; i < root->nr_children; i++){ print_tree(root->children + i, level + 1); A B E void print_tree(struct tree_node *root) { print_tree(root, 0); C F D

Αναδρομική διάσχιση: print_tree() static void print_tree(struct tree_node *root, int level) { int i; for (i=0; i<level; i++) printf("\t"); printf("%s\n", root->name); for (i=0; i < root->nr_children; i++){ print_tree(root->children + i, level + 1); A B E void print_tree(struct tree_node *root) { print_tree(root, 0); C F D

Αναδρομική διάσχιση: print_tree() static void print_tree(struct tree_node *root, int level) { int i; for (i=0; i<level; i++) printf("\t"); printf("%s\n", root->name); for (i=0; i < root->nr_children; i++){ print_tree(root->children + i, level + 1); A B E void print_tree(struct tree_node *root) { print_tree(root, 0); C F D

Αναδρομική διάσχιση: print_tree() static void print_tree(struct tree_node *root, int level) { int i; for (i=0; i<level; i++) printf("\t"); printf("%s\n", root->name); for (i=0; i < root->nr_children; i++){ print_tree(root->children + i, level + 1); A B E void print_tree(struct tree_node *root) { print_tree(root, 0); C F D

Αναδρομική διάσχιση: print_tree() static void print_tree(struct tree_node *root, int level) { int i; for (i=0; i<level; i++) printf("\t"); printf("%s\n", root->name); for (i=0; i < root->nr_children; i++){ print_tree(root->children + i, level + 1); A B E void print_tree(struct tree_node *root) { print_tree(root, 0); C F D

Αναδρομική διάσχιση: print_tree() static void print_tree(struct tree_node *root, int level) { int i; for (i=0; i<level; i++) printf("\t"); printf("%s\n", root->name); for (i=0; i < root->nr_children; i++){ print_tree(root->children + i, level + 1); A B E void print_tree(struct tree_node *root) { print_tree(root, 0); C F D Διάσχιση κατά βάθος (depth-first search)

2 η άσκηση Σύνοψη Διαχείριση διεργασιών Δημιουργία δεδομένου δέντρου διεργασιών με fork() / wait() Δημιουργία αυθαίρετου δέντρου διεργασιών με βάση αρχείο εισόδου που το περιγράφει Διαδιεργασιακή επικοινωνία με σήματα, SIGSTOP / SIGCONT με σωληνώσεις (UNIX pipes)

Σήματα στο UNIX (1) Αποστολή (kill(), raise())

Σήματα στο UNIX (1) Αποστολή (kill(), raise()) Παράδειγμα: if (kill(pid, SIGUSR1) < 0) { perror( kill ); exit(1);

Σήματα στο UNIX (1) Αποστολή (kill(), raise()) Παράδειγμα: if (kill(pid, SIGUSR1) < 0) { perror( kill ); exit(1); Χειρισμός (signal(), με SIG_IGN, SIG_DFL ή handler)

Σήματα στο UNIX (1) Αποστολή (kill(), raise()) Παράδειγμα: if (kill(pid, SIGUSR1) < 0) { perror( kill ); exit(1); Χειρισμός (signal(), με SIG_IGN, SIG_DFL ή handler) Παράδειγμα: void sighandler(int signum) { got_sigusr1 = 1; if (signal(sigusr1, sighandler) < 0) { perror( could not establish SIGUSR1 handler ); exit(1);

Σήματα στο UNIX (2) Αναξιόπιστα Τι θα γίνει αν έρθουν πολλά σήματα; Η συνάρτηση χειρισμού θα τρέξει από 1 έως n φορές Τι θα γίνει αν το σήμα έρθει ενώ η συνάρτηση χειρισμού εκτελείται;

Σήματα στο UNIX (2) Αναξιόπιστα Τι θα γίνει αν έρθουν πολλά σήματα; Η συνάρτηση χειρισμού θα τρέξει από 1 έως n φορές Τι θα γίνει αν το σήμα έρθει ενώ η συνάρτηση χειρισμού εκτελείται; Race conditions: αυτό θα δουλέψει;

Σήματα στο UNIX (2) Αναξιόπιστα Τι θα γίνει αν έρθουν πολλά σήματα; Η συνάρτηση χειρισμού θα τρέξει από 1 έως n φορές Τι θα γίνει αν το σήμα έρθει ενώ η συνάρτηση χειρισμού εκτελείται; Race conditions: αυτό θα δουλέψει; Παράδειγμα: void sighandler(int signum) { got_sigusr1 = 1;... got_sigusr1 = 0; while (!got_sigusr1) pause(); /* Αναμονή έως ότου ληφθεί κάποιο σήμα */

Σήματα στο UNIX (3) Η signal() δεν είναι φορητή Ο handler ακυρώνεται όταν εκτελείται (System V) και πρέπει να επανεγκατασταθεί ή όχι BSD. Στο Linux; εξαρτάται libc vs. kernel Καλύτερη, φορητή λύση: sigaction()

sa.sa_handler = sigchld_handler; sa.sa_flags = SA_RESTART; sigemptyset(&sigset); sa.sa_mask = sigset; if (sigaction(sigchld, &sa, NULL) < 0) { perror("sigaction"); exit(1); Σήματα στο UNIX (3) Η signal() δεν είναι φορητή Ο handler ακυρώνεται όταν εκτελείται (System V) και πρέπει να επανεγκατασταθεί ή όχι BSD. Στο Linux; εξαρτάται libc vs. kernel Καλύτερη, φορητή λύση: sigaction() Παράδειγμα: struct sigaction sa; sigset_t sigset;

Σήματα στο UNIX (4) Χρήσιμες εντολές kill, ps, pstree, killall, grep

Σήματα στο UNIX (4) Χρήσιμες εντολές kill, ps, pstree, killall, grep $ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2... $ ps ef grep oslabg01 grep bash oslabg01 4277 4276 0 12:17 pts/0 00:00:00 bash $ kill -TERM 4277 $ kill -9 4277 $ killall -9 bash

Σήματα στο UNIX (4) Χρήσιμες εντολές kill, ps, pstree, killall, grep $ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2... $ ps ef grep oslabg01 grep bash oslabg01 4277 4276 0 12:17 pts/0 00:00:00 bash $ kill -TERM 4277 $ kill -9 4277 $ killall -9 bash Όλες οι λεπτομέρειες στα manual pages

SIGCHLD SIGCHLD: ένα παιδί άλλαξε κατάσταση Πέθανε κανονικά τερματίστηκε από σήμα έχει σταματήσει λόγω σήματος (SIGTSTP, SIGSTOP)

SIGCHLD SIGCHLD: ένα παιδί άλλαξε κατάσταση Πέθανε κανονικά τερματίστηκε από σήμα έχει σταματήσει λόγω σήματος (SIGTSTP, SIGSTOP) Επιτρέπει στη γονική διεργασία να κάνει waitpid() ασύγχρονα, όταν χρειάζεται Κάτι συμβαίνει σε ένα παιδί Ο πατέρας λαμβάνει SIGCHLD Εκτελεί waitpid() Ιδανικά: πολλές φορές, με WNOHANG

Κώδικας: παράδειγμα χειρισμού SIGCHLD void sigchld_handler(int signum) { pid_t p; int status; /* * Something has happened to one of the children. * We use waitpid() with the WUNTRACED flag, instead of wait(), because * SIGCHLD may have been received for a stopped, not dead child. * * A single SIGCHLD may be received if many processes die at the same time. * We use waitpid() with the WNOHANG flag in a loop, to make sure all * children are taken care of before leaving the handler. */ do { p = waitpid(-1, &status, WUNTRACED WNOHANG); if (p < 0) { perror("waitpid"); exit(1); while (p > 0);

Κώδικας: παράδειγμα χειρισμού SIGCHLD void sigchld_handler(int signum) { pid_t p; int status; /* * Something has happened to one of the children. * We use waitpid() with the WUNTRACED flag, instead of wait(), because * SIGCHLD may have been received for a stopped, not dead child. * * A single SIGCHLD may be received if many processes die at the same time. * We use waitpid() with the WNOHANG flag in a loop, to make sure all * children are taken care of before leaving the handler. */ do { p = waitpid(-1, &status, WUNTRACED WNOHANG); if (p < 0) { perror("waitpid"); exit(1); explain_wait_status(p, status); if (WIFEXITED(status) WIFSIGNALED(status)) /* A child has died */ if (WIFSTOPPED(status)) /* A child has stopped due to SIGSTOP/SIGTSTP, etc... */ while (p > 0);

2 η άσκηση Σύνοψη Διαχείριση διεργασιών Δημιουργία δεδομένου δέντρου διεργασιών με fork() / wait() Δημιουργία αυθαίρετου δέντρου διεργασιών με βάση αρχείο εισόδου που το περιγράφει Διαδιεργασιακή επικοινωνία με σήματα, SIGSTOP / SIGCONT με σωληνώσεις (UNIX pipes)

Αριθμητική έκφραση ως δέντρο * + 5 4 7

4 * (5+7) Αριθμητική έκφραση ως δέντρο * + 5 4 7

4 * (5+7) Αριθμητική έκφραση ως δέντρο * + 5 A B D 4 7 C E

4 * (5+7) Αριθμητική έκφραση ως δέντρο * + 5 4 7 48 A 12 B 5 D 4 7 C E

Αριθμητική έκφραση ως δέντρο * + 5 4 7 48 A 12 B 5 D 4 7 C E 4 * (5+7) Ανάγκη για επικοινωνία παιδί πατέρας

Σωληνώσεις στο UNIX (1) Διεργασία write fd[1] άκρο εγγραφής M read fd[0] Χώρος Χρήστη Χώρος Πυρήνα άκρο ανάγνωσης Ένας από τους βασικότερους μηχανισμούς στο UNIX Μονόδρομη μεταφορά δεδομένων Από το άκρο εγγραφής στο άκρο ανάγνωσης Δημιουργία με pipe(), επικοινωνία με write() και read() Αν η σωλήνωση είναι άδεια; η read() μπλοκάρει

Σωληνώσεις στο UNIX (1) Διεργασία Χώρος Χρήστη Χώρος Πυρήνα int fd[2]; int num1, num2; pipe(fd); write(fd[1], &num1, sizeof(num1)); read(fd[0], &num2, sizeof(num2));

Σωληνώσεις στο UNIX (1) Διεργασία Χώρος Χρήστη Χώρος Πυρήνα άκρο εγγραφής άκρο ανάγνωσης int fd[2]; int num1, num2; pipe(fd); write(fd[1], &num1, sizeof(num1)); read(fd[0], &num2, sizeof(num2));

Σωληνώσεις στο UNIX (1) Διεργασία write fd[1] άκρο εγγραφής M Χώρος Χρήστη Χώρος Πυρήνα άκρο ανάγνωσης int fd[2]; int num1, num2; pipe(fd); write(fd[1], &num1, sizeof(num1)); read(fd[0], &num2, sizeof(num2));

Σωληνώσεις στο UNIX (1) Διεργασία write fd[1] άκρο εγγραφής M int fd[2]; int num1, num2; read fd[0] Χώρος Χρήστη Χώρος Πυρήνα άκρο ανάγνωσης pipe(fd); write(fd[1], &num1, sizeof(num1)); read(fd[0], &num2, sizeof(num2));

Σωληνώσεις στο UNIX (1) Διεργασία write fd[1] read fd[0] Χώρος Χρήστη Χώρος Πυρήνα άκρο εγγραφής άκρο ανάγνωσης int fd[2]; int num1, num2; pipe(fd); write(fd[1], &num1, sizeof(num1)); read(fd[0], &num2, sizeof(num2));

Σωληνώσεις στο UNIX (2) Διεργασία πατέρας Χώρος Χρήστη Χώρος Πυρήνα pipe(fd); fork(); ο πατέρας κλείνει το άκρο ανάγνωσης το παιδί κλείνει το άκρο εγγραφής

Σωληνώσεις στο UNIX (2) Διεργασία πατέρας write fd[1] read fd[0] Χώρος Χρήστη Χώρος Πυρήνα άκρο εγγραφής άκρο ανάγνωσης pipe(fd); fork(); ο πατέρας κλείνει το άκρο ανάγνωσης το παιδί κλείνει το άκρο εγγραφής

Σωληνώσεις στο UNIX (2) Διεργασία πατέρας write fd[1] read fd[0] Χώρος Χρήστη Χώρος Πυρήνα άκρο εγγραφής άκρο ανάγνωσης pipe(fd); fork(); ο πατέρας κλείνει το άκρο ανάγνωσης το παιδί κλείνει το άκρο εγγραφής

Σωληνώσεις στο UNIX (2) Διεργασία πατέρας write fd[1] read fd[0] Διεργασία παιδί write fd[1] read fd[0] Χώρος Χρήστη Χώρος Πυρήνα άκρο εγγραφής άκρο ανάγνωσης pipe(fd); fork(); ο πατέρας κλείνει το άκρο ανάγνωσης το παιδί κλείνει το άκρο εγγραφής

Σωληνώσεις στο UNIX (2) Διεργασία πατέρας write fd[1] Διεργασία παιδί write fd[1] read fd[0] Χώρος Χρήστη Χώρος Πυρήνα άκρο εγγραφής άκρο ανάγνωσης pipe(fd); fork(); ο πατέρας κλείνει το άκρο ανάγνωσης το παιδί κλείνει το άκρο εγγραφής

Σωληνώσεις στο UNIX (2) Διεργασία πατέρας write fd[1] Διεργασία παιδί read fd[0] Χώρος Χρήστη Χώρος Πυρήνα άκρο εγγραφής άκρο ανάγνωσης pipe(fd); fork(); ο πατέρας κλείνει το άκρο ανάγνωσης το παιδί κλείνει το άκρο εγγραφής

Σωληνώσεις στο UNIX (2) Διεργασία πατέρας write fd[1] άκρο εγγραφής M Διεργασία παιδί read fd[0] Χώρος Χρήστη Χώρος Πυρήνα άκρο ανάγνωσης pipe(fd); fork(); ο πατέρας κλείνει το άκρο ανάγνωσης το παιδί κλείνει το άκρο εγγραφής

Σωληνώσεις στο UNIX (2) Διεργασία πατέρας write fd[1] Διεργασία παιδί read fd[0] Χώρος Χρήστη Χώρος Πυρήνα άκρο εγγραφής άκρο ανάγνωσης pipe(fd); fork(); ο πατέρας κλείνει το άκρο ανάγνωσης το παιδί κλείνει το άκρο εγγραφής

Κώδικας: παράδειγμα IPC με UNIX double value; int pfd[2]; pid_t p; if (pipe(pfd) < 0) { perror( pipe ); exit(1); p = fork(); if (p < 0) { perror( fork ); exit(1); else if (p == 0) { pipes else {

Κώδικας: παράδειγμα IPC με UNIX double value; int pfd[2]; pid_t p; if (pipe(pfd) < 0) { perror( pipe ); exit(1); pipes p = fork(); if (p < 0) { perror( fork ); exit(1); else if (p == 0) { if (read(pfd[0], &value, sizeof(value))!= sizeof(value)) { perror( read from pipe ); exit(1); printf( child received value: value = %f\n, value); exit(0); else {

Κώδικας: παράδειγμα IPC με UNIX double value; int pfd[2]; pid_t p; if (pipe(pfd) < 0) { perror( pipe ); exit(1); pipes p = fork(); if (p < 0) { perror( fork ); exit(1); else if (p == 0) { if (read(pfd[0], &value, sizeof(value))!= sizeof(value)) { perror( read from pipe ); exit(1); printf( child received value: value = %f\n, value); exit(0); else { compute_value(&value); if (write(pfd[1], &value, sizeof(value))!= sizeof(value)) { perror( write to pipe ); exit(1); exit(0);

Ερωτήσεις;

Ερωτήσεις; και στη λίστα: OS@lists.cslab.ece.ntua.gr