300 likes | 448 Views
Echtzeitbetriebssysteme Übungen. M.Sc. Alexander Nitsch, M.Sc. Michael Rethfeldt (mit freundlicher Unterstützung von Dr.-Ing. Guido Moritz). Übungsfahrplan. Übung 1 – Hello World. Übung 1 – fork(). #include <stdio.h> #include <stdlib.h> int main(void) { int status; int fork_pid;
E N D
EchtzeitbetriebssystemeÜbungen M.Sc. Alexander Nitsch, M.Sc. Michael Rethfeldt (mit freundlicher Unterstützung von Dr.-Ing. Guido Moritz)
Übung 1 – fork() #include <stdio.h> #include <stdlib.h> int main(void) { int status; int fork_pid; fork_pid=fork() ; if ( fork_pid == 0 ) { printf("* Ich bin der Sohn. *\n"); exit(3); } else if (fork_pid == -1) { printf("Aufruf von fork() gescheitert!\n"); exit(2); } wait(&status); // warten auf Ende des Sohnes printf("wait-Status: 0x%x | 0x%x | 0x%x |\n", status, (status>>8) & 0xff, status & 0xff); return 0; } fork() fork_pid = fork_pid = fork_pid!=0 fork_pid==0 printf() exit() fork_pid!=-1 wait() printf()
Übung 1 – Speicherbelegung Speicher Speicher Code beider Prozesse Code Code Daten Daten Vater Daten des Vaters Daten Daten des Sohnes
Übung 1 – Wieviele Söhne werden erzeugt? Vater Vater Sohn1 Sohn1 1. fork() printf() 1. fork() Sohn2 Sohn3 Sohn2 2. fork() 2. fork() printf() 2. fork() printf() ENDE
Sohn 3 PID: 3 Sohn 1 PID: 2 Sohn 4 PID: 4 Vater PID=1 Sohn 5 PID: 4 Sohn 2 PID: 3 Sohn 6 PID: 5 Übung 2 Frage: Kann es sein, dass PID=3 und PID=4 zweimal vergeben werden?
Typischer Prozessbaum 3774 ? Ss 0:00 /usr/sbin/privoxy --user privoxy privoxy --pidfile 3779 ? Ss 0:00 /usr/sbin/sshd -o PidFile=/var/run/sshd.init.pid 10341 ? Ss 0:00 \_ sshd: bj [priv] 10343 ? S 0:00 | \_ sshd: bj@pts/3 10344 pts/3 Ss+ 0:00 | \_ -bash 27959 ? Ss 0:00 \_ sshd: bj [priv] 27961 ? S 0:00 \_ sshd: bj@pts/4 27962 pts/4 Ss 0:00 \_ -bash 28213 pts/4 R+ 0:00 \_ ps -fax 3834 ? S 0:00 /bin/sh /usr/bin/mysqld_safe --user=mysql 4016 ? S 0:00 \_ /usr/sbin/mysqld --basedir=/usr -- 4682 ? S 0:00 /usr/lib/AntiVir/antivir --updater-daemon 4770 ? Ss 0:00 /usr/sbin/cupsd 4815 ? Ss 0:01 /usr/sbin/nscd 4835 ? Ss 0:00 /usr/sbin/smbd -D -s /etc/samba/smb.conf 4842 ? S 0:00 \_ /usr/sbin/smbd -D -s /etc/samba/smb.conf 7378 ? S 0:04 \_ /usr/sbin/smbd -D -s /etc/samba/smb.conf 27995 ? S 0:00 \_ /usr/sbin/smbd -D -s /etc/samba/smb.conf
Übung 2 #include <stdio.h> int main(void) { int var; printf(“PID(Father)=%d, var=%d\n", getpid(), var); if ( fork() == -1 ) { fprintf( stderr, "Aufruf fork() gescheitert!\n" ); } else { var++; printf(“PID=%d, var=%d\n", getpid(), var); if ( fork() == -1 ) { fprintf( stderr, "Fehler beim 2. fork()!\n"); } else { var++; printf(“PID=%d, var=%d\n", getpid(), var); } } return 0; }
Übung 2 Typische Ausgaben nach stdout PID(Father): 5179, var=0 PID=5180, var=1 PID=5181, var=2 PID=5180, var=2 PID=5179, var=1 PID=5182, var=2 PID=5179, var=2
Übung 2: Execl() Vater fork() Vater Sohn fork() ExternesProgramm Vater
Übung 2: Execl • Fork() dient der Prozessverzweigung • Execl() dient dem Starten des externen Programmes • Nebeneffekt: • Alle Daten des Vaters werden gelöscht • Alle Filedescriptoren des Vaters werden freigegeben • Anwendung: • Starten von Programmen, z.B. init
Execl()-Parametermapping int execl(const char *path, const char *arg, ...); Ausführbare Datei int execl(“/bin/ls”, “ls”, “-lias”, NULL);
Übung 3 • Fork() erzeugt Kopie aller Daten des Prozesses A • Direkter Datenaustausch zwischen Prozessen nicht möglich • Ausweg: Pipe des Betriebssystems Prozess A Prozess B Betriebssystem
Übung 3 • Array aus zwei File-Descriptoren: int fd[2] • Erzeugen der Pipe mit pipe() • Vererbung von fd[2] durch fork() an Sohn • Lesen: fd[0] Schreiben: fd[1] • Schließen der korrespondierenden File-Descriptoren • Writer schließt fd[0] • Reader schließt fd[1] Prozess A Prozess B Betriebssystem read(fd[0]); write(fd[1]);
Übung 3 Prozess A Prozess B Initialisieren einer Pipe fd[2], File-Zähler=2 pipe(fd) Erzeugen des Sohn-Prozesses, File-Zähler=4 fork() Schließen des Lesedescriptors (fd[0]) und des Schreibdescriptors (fd[1]), File-Zähler=2 close(fd[0]) close(fd[1]) write(fd[1]) read(fd[0]) Datenaustausch über Pipe
Übung 3 • Signale können jederzeit auftreten • Nebenläufige Fehlerbehandlung erfolgt in Signal-Handlern • Behandlung des Signals, sodass Hauptprogramm fehlerfrei weiterläuft ! Idealer Programmverlauf Unterbrochener Programmverlauf Signal Signal-behandlung
Übung 4 • Systemweiten eindeutigen Key erzeugen • Öffnen der Nachrichtenwarteschlange (Messagequeue) • Projektidentifier proj_id kennzeichnet Nummer der Pipe Prozess A Prozess B Betriebssystem ftok(…,1) msgget() msgrcv(); ftok(…,1) ftok(…,2) msgget() msgget() msgsnd() Proj_id=1 Proj_id=2 Prozess C ftok(…,2) msgget() msgrcv();
Übung 4 Was ist an welcher Schreibweise günstiger?
Übung 5 – Casting von Funktionszeigern Linke Variante ist inkorrekt, da Rückgabetyp von thread_start falsch ist!
Übung 7 – Deadlock • Zwei Prozesse betreten in unterschiedlicher Reihenfolge zwei kritische Abschnitte • Kritischer Punkt: Threadumschaltung, wenn einer der Threads in einem kritischen Abschnitt ist DEADLOCK
Übung 7 – Prioritäteninversion • Ein höher priorisierter Thread wird durch einen niedriger priorisierten Thread unterbrochen. • Bezeichnung: Direct Blocking
Übung 7 – Priority Inheritance Protocol • PL wird auf Priorität von PH angehoben, wenn PH das Mutex anfordert • PM kommt nicht zum Zuge • Zeit im kritischen Abschnitt wird verringert • Keine Kenntnis der nutzenden Threads nötig
Übung 7 – Priority Ceiling Protocol (PCP) Der Grundgedanke bei PCP ist, sicherzustellen, dass ein Prozess, der andere Prozesse in kritischen Abschnitten unterbricht und einen eigenen betritt, eine höhere Priorität in diesem Abschnitt garantieren muss als die Prioritäten aller unterbrochenen kritischen Abschnitte. Kann diese Bedingung nicht erfüllt werden, wird der Prozess blockiert. • Vermeidung von Deadlocks und Mehrfachvererbungen (Chained Blocking) [Raj91] • Einführung einer Ceiling-Konstanten c(Sj) pro Semaphor Sj • c(Sj) = Priorität des höchst-prioren Prozesses, der das Semaphor nutzen wird • Prozess P kann ein Semaphor S nur setzen, wenn seine Priorität größer als die der Ceiling-Konstanten aller nicht von P zur Zeit belegten Semaphoren ist (außer er besitzt bereits das höchst-priore Semaphor) • Kann ein Prozess ein Semaphor nicht setzen, wird die Priorität des unterbrochenen Prozessesauf die des unterbrechenden Prozesses erhöht • Einführung einer System-Ceiling-Konstanten S* zur einfacheren Berechnung Maximum aller Semaphor-Ceiling-Konstanten, die gerade genutzt werden
Übung 7 – Beispiel PCP P0 P1 P2 3 Prozesse (P0, P1 & P2) konkurrieren über 3 Semaphoren (S0, S1 & S2) Statische Prio S*=0 S*=2 S*=0 S*=0 Prio 3 2 1 S*=3 Prio-Vererbung P1P2 S*=2 Da alle Semaphore anfangs noch komplett frei sind, ist die Ceiling des Systems S* noch 0 P2 bekommt in jedem Fall S2 danach ist S* = S2 = 2 (S2 ‚begründet‘ S*)
Übung 7 – Deadlockvermeidung Prio(P1) = Prio(P2) = 1 C(S1) = C(S2) = 1