Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Echtzeitbetriebssysteme Übungen

Ähnliche Präsentationen


Präsentation zum Thema: "Echtzeitbetriebssysteme Übungen"—  Präsentation transkript:

1 Echtzeitbetriebssysteme Übungen
M.Sc. Alexander Nitsch, M.Sc. Michael Rethfeldt (mit freundlicher Unterstützung von Dr.-Ing. Guido Moritz)

2 Übungsfahrplan Nr. Beschreibung Inhalte 1
Erzeugen und Starten von Prozessen I Von Threads und Prozessen 2 Erzeugen und Starten von Prozessen II 3 Pipes & Signale Inter-Prozess-Kommunikation (IPC) 4 Messagequeues, Shared Memory 5 POSIX & Threads Inter-Prozess-Synchronisation (IPS) 6 Mutexe, Conditions & Semaphore unter POSIX 7 Synchronisationsprotokolle & Deadlocks Schedulinganalysen 8 Schedulinganalyse Sensornetzwerke: -> Was ist Ubiquitous Computing , Sensorknoten, Sensornetzwerk, Beispiele Herausforderungen: -> Probleme bei der Umsetzung

3 Übung 1 – Hello World ////////////////////////////////////////////////////////// // Veranstaltung: Echtzeitbetriebssysteme // Dozent: Dr.-Ing. Frank Golatowski // Übungsleiter: Dipl.-Ing. Guido Moritz // Übung: // Aufgabe: // Name: aufgabe1.c // Beschreibung: Hello World Ausgabe #include <stdio.h> int main(int argc, char *argv[]) { printf("Hello world!\n"); }

4 Übung 1 – fork() fork() fork_pid = fork_pid = fork_pid!=0 fork_pid==0
#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()

5 Übung 1 – Starten von Prozessen

6 Übung 1 – Speicherbelegung
Code beider Prozesse Code Code Daten Daten Vater Daten des Vaters Daten Daten des Sohnes

7 Übung 1 – Wieviele Söhne werden erzeugt?
int main(int argc, char *argv[]) { fork(); } int main(int argc, char *argv[]) { switch ( fork() ) { case 0: printf(„Sohn erzeugt\n“); break; default: switch ( fork() ) { case 0: printf(„Sohn erzeugt\n“); default: printf(„Vater\n“); }

8 Übung 1 – Wieviele Söhne werden erzeugt?
Vater Vater Sohn1 Sohn1 1. fork() 1. fork() printf() Sohn2 Sohn3 2. fork() 2. fork() Sohn2 2. fork() printf() printf() ENDE

9 Übung 2 Sohn 3 Sohn 1 PID: 2 Sohn 4 PID: 4 Vater PID=1 Sohn 5 Sohn 2
Frage: Kann es sein, dass PID=3 und PID=4 zweimal vergeben werden?

10 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 :00 | \_ sshd: 10344 pts/3 Ss+ 0:00 | \_ -bash 27959 ? Ss 0:00 \_ sshd: bj [priv] 27961 ? S : \_ sshd: 27962 pts/4 Ss 0: \_ -bash 28213 pts/4 R : \_ ps -fax 3834 ? S :00 /bin/sh /usr/bin/mysqld_safe --user=mysql 4016 ? S :00 \_ /usr/sbin/mysqld --basedir=/usr -- 4682 ? S :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 :00 \_ /usr/sbin/smbd -D -s /etc/samba/smb.conf 7378 ? S :04 \_ /usr/sbin/smbd -D -s /etc/samba/smb.conf 27995 ? S :00 \_ /usr/sbin/smbd -D -s /etc/samba/smb.conf

11 Ü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); fprintf( stderr, "Fehler beim 2. fork()!\n"); return 0;

12 Ü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

13 Übung 2: Execl() Vater fork() Vater Sohn fork() Vater
Externes Programm

14 Ü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

15 Execl()-Parametermapping
int execl(const char *path, const char *arg, ...); Execl-Parameter Argument der Main-Funktion Anzahl der Parameter-1 argn const char *arg argv[0] …. argv[1] Ausführbare Datei int execl(“/bin/ls”, “ls”, “-lias”, NULL); Argument der Main-Funktion Argumente argn 2 argv[0] ls argv[1] -lias

16 Übung 3 Prozess A Prozess B
Betriebssystem Fork() erzeugt Kopie aller Daten des Prozesses A Direkter Datenaustausch zwischen Prozessen nicht möglich Ausweg: Pipe des Betriebssystems

17 Übung 3 Prozess A Prozess B
Betriebssystem write(fd[1]); read(fd[0]); 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]

18 Ü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

19 Idealer Programmverlauf Unterbrochener Programmverlauf
Übung 3 Idealer Programmverlauf Unterbrochener Programmverlauf Signale können jederzeit auftreten Nebenläufige Fehlerbehandlung erfolgt in Signal-Handlern Behandlung des Signals, sodass Hauptprogramm fehlerfrei weiterläuft ! Signal Signal-behandlung

20 Übung 4 Prozess A Prozess B Prozess C
Betriebssystem ftok(…,1) msgget() msgrcv(); ftok(…,1) ftok(…,2) msgget() msgsnd() Proj_id=1 Proj_id=2 Prozess C ftok(…,2) msgget() msgrcv(); Systemweiten eindeutigen Key erzeugen Öffnen der Nachrichtenwarteschlange (Messagequeue) Projektidentifier proj_id kennzeichnet Nummer der Pipe

21 Übung 4 Was ist an welcher Schreibweise günstiger? void main(void) {
pid_t p=getpid(); switch ( fork() ) case 0: printf(„The son!\n“); break; default: printf(„The father!\n“); printf(„pid: %d\n“,p); } default: {

22 Übung 5 – Casting von Funktionszeigern
Casting notwendig: Kein Casting notwendig: int main(int argc, char *argv[]) { pthread_create( &thread, &attr, (void*)&thread_start, 0); } void thread_start(void *ptr) return; thread_start, 0); void* thread_start(void *ptr) return 0; Linke Variante ist inkorrekt, da Rückgabetyp von thread_start falsch ist!

23 Übung 5 – Typen von Funktionszeigern
Zeigerübergabe von Funktionen ohne typedef Zeigerübergabe von Funktionen mit typedef #include <stdio.h> int printme(const char *msg); void thread1(int (*function)(const char *ptr) ); void thread2(int (*)(const char *ptr) ); int main(int argc, char *argv[]) { thread1(printme); thread2(printme); return 0; } void thread1(int (*function)(const char *ptr) ) { function("Hans im Glück\n"); void thread2(int (*function)(const char *ptr) ) { function("Der Wolf im Schafspelz\n"); int printme(const char *msg) { printf(msg); typedef int (*CALLBACK)(const char *ptr); void thread1(CALLBACK function); void thread2(CALLBACK); void thread1(CALLBACK function) void thread2(CALLBACK function)

24 Übung 6 – Condition Variablen
Aktives Warten Warten mit Conditionvariablen void* reader_function(void *ptr) { char a=0; while( a!= 'q' ) { pthread_mutex_lock( &mutex ); if ( buffer_has_item == 1) { a=buffer; if ( a != 'q' ) consume_item(a,count); buffer_has_item = 0; } pthread_mutex_unlock( &mutex ); return 0; while ( buffer_has_item != 1) pthread_cond_wait( &cond_buffer_full, &mutex); a=buffer; pthread_cond_signal( &cond_buffer_empty);

25 Ü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

26 Übung 7 – Prioritäteninversion
Ein höher priorisierter Thread wird durch einen niedriger priorisierten Thread unterbrochen. Bezeichnung: Direct Blocking

27 Übung 7 – Pass Through Blocking
Prozess Priorität Periode Offset Deadline Rechenzeit Auslastung PH 3 (hoch) 120 20 30 0,25 PM 2 (mittel) 40 PL 1 (niedrig) 50 0,42

28 Ü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

29 Ü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 Prozesses auf 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

30 Übung 7 – Beispiel PCP P0 P1 P2 3 Prozesse (P0, P1 & P2) konkurrieren über 3 Semaphoren (S0, S1 & S2) Prozess Priorität Periode Offset Deadline Rechenzeit Auslastung P0 3 (hoch) 150 50 40 0,27 P1 2 (mittel) 20 30 0,2 P2 1 (niedrig) 70 0,47  Statische Prio S*=2 S*=0 S*=0 S*=0 Prio 3 2 1 S*=3 Prio-Vererbung P1P2 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*)

31 Übung 7 – Deadlockvermeidung
Prio(P1) = Prio(P2) = 1 C(S1) = C(S2) = 1


Herunterladen ppt "Echtzeitbetriebssysteme Übungen"

Ähnliche Präsentationen


Google-Anzeigen