Prozesse und Threads
Prozesse und Threads
Prozesse und Threads
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
Kapitel 2<br />
<strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong><br />
2.1 <strong>Prozesse</strong><br />
2.2 <strong>Threads</strong><br />
2.3 Interprozesskommunikation<br />
2.4 Klassische Probleme der Interprozesskommunikation<br />
2.5 Scheduling
<strong>Prozesse</strong><br />
Das Prozessmodell<br />
Unterschied Prozess / Programm<br />
Prozess ist eine Aktivität<br />
Besteht aus Programm, Input, Output <strong>und</strong> Zustand<br />
a) Multiprogramming von vier Programmen<br />
b) Konzeptionelles Modell von vier unabhängigen sequentiellen <strong>Prozesse</strong>n<br />
c) Zu einem Zeitpunkt ist nur ein Programm aktiv.<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 2
<strong>Prozesse</strong>rzeugung<br />
• OS muss sicherstellen, dass alle wichtigen <strong>Prozesse</strong><br />
existieren.<br />
• Manchmal: alle <strong>Prozesse</strong> die jemals benötigt werden,<br />
werden beim Startup erzeugt<br />
• Im allgemeinen: Möglichkeit zur Erzeugung / Beendigung<br />
erforderlich<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 3
<strong>Prozesse</strong>rzeugung<br />
Ereignisse, die die Erzeugung eines <strong>Prozesse</strong>s auslösen<br />
1. Initialisierung des Systems (boot)<br />
2. Systemaufruf zum Erzeugen eines <strong>Prozesse</strong>s durch einen<br />
anderen Prozess<br />
3. Benutzeranfrage, einen neuen Prozess zu erzeugen<br />
4. Start eines Batch Jobs<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 4
<strong>Prozesse</strong>rzeugung<br />
Booten<br />
Mehrere <strong>Prozesse</strong> werden gestartet<br />
• <strong>Prozesse</strong> zur Interaktion mit Anwender<br />
• <strong>Prozesse</strong> für bestimmte Funktionen<br />
– Email-service<br />
– Drucker-Warteschlange<br />
– Firewall<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 5
Windows Taskmanager<br />
Prozessliste<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 6
Prozessbeendigung<br />
Bedingungen, die zum Beenden von <strong>Prozesse</strong>n führen<br />
1. Normales Beenden (freiwillig)<br />
2. Beenden auf Gr<strong>und</strong> eines Fehlers (freiwillig)<br />
3. Beenden auf Gr<strong>und</strong> eines schwerwiegenden<br />
Fehlers(unfreiwillig)<br />
4. Beenden durch einen anderen Prozess (unfreiwillig)<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 7
Prozesshierarchien<br />
• Elternprozess erzeugt Kindprozess. Kindprozess kann weitere<br />
<strong>Prozesse</strong> erzeugen. In UNIX ist das eine Prozessfamilie<br />
• Unter Windows gibt es kein Konzept einer Prozesshierarchie,<br />
alle <strong>Prozesse</strong> sind gleichwertig.<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 8
Prozesszustände (1)<br />
1. Prozess blockiert wegen<br />
Eingabe<br />
2. Schedular wählt einen<br />
anderen Prozess<br />
3. Schedular wählt diesen<br />
Prozess<br />
4. Eingabe vorhanden<br />
• Mögliche Prozesszustände<br />
– rechnend (running)<br />
– blockiert (blocked)<br />
– rechenbereit (ready)<br />
• Es existieren die dargestellten Übergänge zwischen diesen<br />
Zuständen<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 9
Prozesszustände (2)<br />
• Die unterste Schicht eines prozessstrukturierten Betriebssystems<br />
behandelt Interrupts <strong>und</strong> Scheduling<br />
• Oberhalb befinden sich sequentielle <strong>Prozesse</strong><br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 10
Implementierung von <strong>Prozesse</strong>n<br />
Einige Felder eines typischen<br />
Eintrags einer Prozesstabelle<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 11
Umschalten zwischen <strong>Prozesse</strong>n<br />
Context Switch<br />
Aufgaben der untersten Schicht des Betriebssystems bei<br />
Auftreten einer Unterbrechung<br />
1. Hardware sichert Befehlszähler etc<br />
2. Hardware holt neuen Befehlszähler vom Interruptvektor<br />
3. Assemblerfunktion speichert Register<br />
4. Assemblerfunktion erzeugt neuen Stack<br />
5. C-Unterbrechungsroutine läuft (puffert Ein/- Ausgaben)<br />
6. Schedular sucht nächsten Prozess<br />
7. C-Funktion kommt zur Assemblerfunktion zurück<br />
8. Assemblerfunktion startet neuen aktuellen Prozess<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 12
Schritte für den Systemaufruf<br />
Adresse<br />
0xFFFFFFFF<br />
Return zum Aufrufer<br />
Systemaufruf in den Kern<br />
5. Put code for read in register<br />
Bibliotheksprogramm<br />
read<br />
4.<br />
10.<br />
Benutzerraum<br />
11. Erhöhe Stackpointer<br />
6.<br />
Rufe read auf<br />
3. Push fd<br />
Benutzerprogramm<br />
ruft read auf<br />
count = read (fd,<br />
buffer, nbytes<br />
2. Push &buffer<br />
1. Push nbytes<br />
9.<br />
fd : filedescriptor<br />
buffer : Ziel<br />
nbytes : Länge<br />
Kernadressraum<br />
Verteilung<br />
7. 8.<br />
Systemaufrufbehandlung<br />
13
<strong>Threads</strong><br />
Das Threadmodell (1)<br />
• Traditionelles Modell:<br />
Prozess hat<br />
• einen Adressraum<br />
• einen Ausführungsfaden<br />
• Manchmal ist es<br />
wünschenswert, mehrere<br />
Ausführungsfäden zu haben<br />
Drei <strong>Prozesse</strong> mit jeweils einem Thread<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 14
<strong>Threads</strong><br />
Das Threadmodell (2)<br />
• Traditionelles Modell: Prozess hat<br />
• einen Adressraum<br />
• einen Ausführungsfaden<br />
• Manchmal ist es wünschenswert,<br />
mehrere Ausführungsfäden zu<br />
haben<br />
• wie eigene <strong>Prozesse</strong>, aber<br />
gemeinsamer Adressraum<br />
Ein Prozess mit drei <strong>Threads</strong><br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 15
Das Threadmodell (3)<br />
1. Spalte: Elemente werden zwischen den <strong>Threads</strong> eines<br />
<strong>Prozesse</strong>s aufgeteilt<br />
2. Spalte: Thread-eigene Elemente<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 16
Das Threadmodell (3)<br />
Jeder Thread hat seinen eigenen Stack<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 17
Einsatz von <strong>Threads</strong> (1)<br />
Ein Textprogramm mit drei <strong>Threads</strong><br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 18
Einsatz von <strong>Threads</strong> (2)<br />
Dienstag, 30. April<br />
2013<br />
Ein Web-Server mit mehreren <strong>Threads</strong><br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 19
Einsatz von <strong>Threads</strong> (3)<br />
• Grober Auszug des Codes zur vorherigen Folie.<br />
(a) Dispatcher thread<br />
(b) Worker thread<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 20
Einsatz von <strong>Threads</strong> (4)<br />
Drei Möglichkeiten, einen Server zu bauen:<br />
Modell<br />
<strong>Threads</strong><br />
<strong>Prozesse</strong> (ein Thread)<br />
Endlicher Automat<br />
Eigenschaften<br />
Parallel, blockierende Systemdienste<br />
Nicht parallel, blockierende<br />
Systemdienste<br />
Parallel, nicht blockierende<br />
Systemdienste<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 21
Einsatz von <strong>Threads</strong> (5)<br />
Was <strong>Threads</strong> zu bieten haben:<br />
• Sie ermöglichen es, das Konzept von sequenziellen <strong>Prozesse</strong>n,<br />
die blockierende Systemaufrufe (z.B. für Platten E/A) machen,<br />
beizubehalten <strong>und</strong> troztdem Parallelität zu erzielen<br />
• Blockierende Systemaufrufe vereinfachen die Programmierung<br />
<strong>und</strong> die Parallelität verbessert die Performance<br />
• Der Einzel-Thread-Server behält die Einfachheit von<br />
blockierenden Systemaufrufen bei, gibt jedoch die Performance<br />
auf.<br />
• Der dritte Ansatz bringt hohe Performance durch Parallelität,<br />
benutzt aber nicht blockierende Aufrufe <strong>und</strong> ist deshalb<br />
schwieriger zu programmieren<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 22
Realisierung von <strong>Threads</strong> im<br />
Benutzeradressraum (1)<br />
Ein Benutzer-Level<br />
Thread Paket<br />
Vorteile:<br />
• kann auch auf Betriebssystemen<br />
realisiert werden, die <strong>Threads</strong> nicht<br />
unterstützen<br />
• Umschalten zwischen <strong>Threads</strong> geht<br />
vergleichsweise schnell<br />
Run-time system –<br />
Laufzeitsystem, enthält eine<br />
Sammlung von Prozeduren,<br />
die auch <strong>Threads</strong> verwalten<br />
(thread_create, thread_exit,...)<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 23
Realisierung von <strong>Threads</strong> im<br />
Benutzeradressraum (2)<br />
Ein Benutzer-Level<br />
Thread Paket<br />
Dienstag, 30. April<br />
2013<br />
Probleme:<br />
• Ruft ein Thread einen blockierenden<br />
Systemaufruf auf (z.B. read von<br />
Tastatur), werden alle Thread blockiert<br />
• Systemaufrufe müssten nicht<br />
blockierend implementiert werden <strong>und</strong><br />
Anwendungsprogramme müssten dafür<br />
modifiziert werden (sehr aufwendig)<br />
• Seitenfehler eines <strong>Threads</strong> blockieren<br />
ebenso alle <strong>Threads</strong><br />
• Startet ein Thread, kommt kein<br />
anderer an die Reihe, bis der erste von<br />
sich aus die CPU freigibt<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 24
Realisierung von <strong>Threads</strong> im Kern(1)<br />
Ein Thread Paket,<br />
verwaltet vom Kern<br />
Kern hat Thread-Tabelle, die<br />
alle <strong>Threads</strong> im System<br />
verwaltet<br />
Zur Sicherheit: Exkurs über<br />
Betriebssystemkern!<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 25
Betriebssystemkern (1)<br />
Wikipedia: Ein Betriebssystemkern oder Systemkern (engl. kernel<br />
) ist der zentrale Bestandteil eines Betriebssystems. In ihm ist die<br />
Prozess- <strong>und</strong> Datenorganisation festgelegt, auf der alle weiteren<br />
Softwarebestandteile des Betriebssystems aufbauen. Er ist meist in<br />
der untersten Softwareschicht, hat also Zugriff auf die Hardware.<br />
Die Konstruktion eines Betriebssystemkerns gehört zum<br />
Themenbereich der Informatik <strong>und</strong> des Softwareengineerings.<br />
Gängige Anforderungen an einen Systemkern sind<br />
Parallelverarbeitung verschiedener Aufgaben (Multitasking),<br />
Einhaltung zeitkritischer Grenzen, Offenheit für unterschiedlichste<br />
Anwendungen <strong>und</strong> Erweiterungen.<br />
Nicht zum Systemkern gehörende Teile werden als Userland<br />
bezeichnet.<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 26
Betriebssystemkern (2)<br />
Bestandteile<br />
Ein Systemkern ist in Schichten (oder Layer, siehe Schichtenmodell) aufgebaut,<br />
wobei die unteren (maschinennahen) Schichten die Basis für die darüberliegenden<br />
bilden. Die oberen Schichten können Funktionen der unteren Schichten aufrufen,<br />
aber nicht umgekehrt.<br />
Folgende Schichten sind vorhanden (von unten nach oben):<br />
• Schnittstelle zur Hardware (Geräte, Speicher, Prozessoren)<br />
• Speicherverwaltung (evtl. einschließlich virtuellem Hauptspeicher)<br />
• Prozessverwaltung (auch Scheduler genannt)<br />
• Geräteverwaltung (auch Device Management genannt)<br />
• Dateisysteme<br />
Wenn alle diese Funktionen im Systemkern selbst integriert sind, spricht man von<br />
einem monolithischen Kernel. Bei einem Mikrokernel finden wesentliche Teile in<br />
getrennten <strong>Prozesse</strong>n statt. Daneben, bzw. zwischen den beiden liegend, gibt es<br />
noch den sogenannten Makrokernel.<br />
Auf jeden Fall außerhalb des Kernels laufen die Anwenderprozesse, die sich der<br />
vom Kernel angebotenen Funktionen bedienen, um mit der Maschine zu<br />
kommunizieren.<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 27
Betriebssystemkern (3)<br />
Aufgaben eines Kernels :<br />
• Schnittstelle zu Anwenderprogrammen (Starten, Beenden, Ein-/Ausgabe,<br />
Speicherzugriff)<br />
•Kontrolle des Zugriffs auf Prozessor, Geräte, Speicher (Scheduler, Gerätetreiber,<br />
Speicherschutz). Möglichst alleiniger Zugriff des Kernels auf diese Ressourcen.<br />
•Verteilung der Ressourcen, etwa der Prozessorzeit(en) (bzw. der Prozessoren) auf<br />
die Anwenderprogramme<br />
•Strukturierung der Ressourcen, etwa Abbildung von Dateisystemen auf<br />
blockorientierte Geräte wie Festplatten, Netzwerkprotokoll-Stack auf<br />
Netzwerkkarten.<br />
•Auflösung von Zugriffskonflikten, etwa Verriegelung bei Mehrprozessorsystemen,<br />
Warteschlangen bei knappen Ressourcen<br />
•Virtualisierung der Ressourcen (Prozessor: <strong>Prozesse</strong>, Festplatte: Dateien,<br />
Netzwerkkarte: z. B. Sockets, Speicher: virtueller Speicher, Geräte: Spezialdateien)<br />
•Überwachung von Zugriffsrechten auf Dateien <strong>und</strong> Geräte bei<br />
Mehrbenutzersystemen<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 28
Betriebssystemkern (4)<br />
Schichten eines Unix Betriebssystems<br />
User<br />
Interface<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 29
Betriebssystemkern (5)<br />
Kernel Mode – User Mode<br />
Kernel <strong>und</strong> user space sind<br />
unterschiedliche Teile des<br />
Adressraumes. User space ist<br />
reservierter Bereich für<br />
applikationen (jede einen eigenen<br />
Bereich).<br />
Kernel space ist auch ein reservierter Bereich, jedoch nur einer<br />
für alle Anwendungen, die dort nicht schreiben können. Nur das<br />
Betriebssystem kann den Prozessor auf kernel mode umschalten<br />
<strong>und</strong> auf diesen Bereich zugreifen... Anwendungen laufen<br />
dagegen normalerweise nur im user mode des prozessors, <strong>und</strong><br />
verwenden damit einen eingeschränkten Befehlssatz ist.<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 30
Dienstag, 30. April<br />
2013<br />
Betriebssystemkern (6)<br />
CPU- Betriebsarten: Kernel Mode – User Mode<br />
Das Programmstatuswort der<br />
CPU enthält die aktuelle<br />
Betriebsart: kernel mode, user<br />
mode Damit wird ein<br />
Schutzsystem realisiert<br />
kernel mode: - privilegierte Betriebsart (nur für Betriebssystem)<br />
- alle Instruktionen sind erlaubt, inbes. IO auf Hardware<br />
user mode:- nicht privilegierte Betriebsart<br />
- nicht alle Instruktionen sind erlaubt (z.B. Zugriff auf Ein-/Ausgabe)<br />
- nicht alle Register dürfen verändert werden (z.B. Register für<br />
Speicherkonfiguration)<br />
Umschaltung in Kernmodus: mittels Interrupt (über SW oder HW ausgelöst)<br />
Umschaltung in Benutzermodus: mittels Maschinenbefehl bzw. PSW-<br />
Modifikation<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 31
Realisierung von <strong>Threads</strong> im Kern(2)<br />
Ein Thread Paket,<br />
verwaltet vom Kern<br />
Kern hat Thread-Tabelle, die alle<br />
<strong>Threads</strong> im System verwaltet<br />
Thread-Tabelle enthält<br />
Informationen über Register,<br />
Zustand... der einzelnen <strong>Threads</strong><br />
Alle Aufrufe, die blockieren können,<br />
sind als Systemaufrufe realisiert mit<br />
höheren Kosten als Aufrufe im<br />
Laufzeitsystem – aber:<br />
wenn ein Thread blockiert, hat der<br />
Kern die Möglichkeit, einen anderen<br />
(prozesseigegnen oder fremden)<br />
Thread zu starten<br />
Fazit: flexibel, aber teuer<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 32
Hybride Implementierung<br />
Multiplexen von Benutzer-Level-<strong>Threads</strong> in Kern-<strong>Threads</strong><br />
= Versuch, die Vorteile beider Implementierungen zu<br />
verbinden<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 33
Scheduler Activations<br />
• Ziel: – Verbindung der Funktionalität von Kern-<strong>Threads</strong> mit der Performance<br />
von Benutzeradressraum <strong>Threads</strong><br />
• Vermeiden von unnötigen user/kernel Umschaltungen<br />
• Kern ordnet jedem Prozess virtuelle Prozessoren zu <strong>und</strong> veranlasst das<br />
Laufzeitsystem (im Benutzeradressraum) den Prozessoren <strong>Threads</strong> zuzuordnen<br />
(geht auch bei Multiprozessorsystemen)<br />
• Gr<strong>und</strong>idee: Wenn der Kern weiss, dass ein Thread durch einen blockierenden<br />
Systemaufruf oder Seitenfehler blockiert hat, benachrichtigt er das<br />
Laufzeitsystem (Upcall) Das Laufzeitsystem kann seine <strong>Threads</strong> darauf hin neu<br />
schedulen, also den gegenwärtigen Thread als blockiert markieren <strong>und</strong> einen<br />
anderen starten<br />
• Problem: F<strong>und</strong>amental reliance on kernel (lower layer) calling procedures in<br />
user space (higher layer)<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 34
Pop-Up <strong>Threads</strong><br />
Erzeugen eines neuen <strong>Threads</strong>, wenn eine Nachricht eintrifft<br />
(a) bevor die Nachricht eintrifft<br />
(b) nachdem die Nachricht eintrifft<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 35
Multithreading<br />
• Üblich: zuerst nur ein Thread<br />
• Startet weitere threads(z.B. thread_create (proc_name))<br />
• Manchmal hierarchisch, manchmal flach<br />
• Wenn thread fertig: thread_exit<br />
• Warten auf thread-Ende: thread_wait<br />
• CPU freiwillig hergeben: thread_yield<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 36
Posix Thread Beispiel – 1<br />
Main 1<br />
PROGRAM For<strong>Threads</strong><br />
!<br />
! Funktionsbeschreibung:<br />
! Thread Testprogramm<br />
!<br />
! Programm kreiert <strong>und</strong> startet mehrere <strong>Threads</strong>:<br />
! - Worker wird mehrmals kreiert (Master-Worker) <strong>und</strong> gestartet.<br />
! Diese Workerthreads arbeiten periodisch mit Hilfe eines Timers.<br />
! Sie stoßen wiederum alle den selben Thread an<br />
! - Thread2 ist der mittels pthread_cond_signal von Worker ange-<br />
! stossene Thread, der in einer Endlosschleife mit pthread_cond_wait<br />
! auf Aufträge wartet. Er muss vom Hauptprogramm mit pthread_cancel<br />
! explizit beendet werden<br />
! - Thread3 läuft als unabhängiger Thread <strong>und</strong> führt eine Anzahl Ite-<br />
! rationen aus. Für ihn werden Scheduling-Parameter (Priorität)<br />
! gesetzt.<br />
! - Das Programm endet erst, wenn alle <strong>Threads</strong> abgearbeitet oder beendet sind.<br />
! Geprüft wird dies mit pthread_join.<br />
!<br />
!<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 37
Posix Thread Beispiel – 2<br />
benutzte Posix Funktionen<br />
! Functions:<br />
! pthread_cond_init Conditionvariable erzeugen <strong>und</strong> mit<br />
! Defaultwert initialisieren<br />
! pthread_cond_broadcast Alle Thread, die auf eine bestimmte<br />
! Condition-Variable hören, benachrichtigen<br />
! pthread_cond_signal Einen Thread, der auf eine bestimmte<br />
! Condition-Variable hört, benachrichtigen<br />
! pthread_create Einen Thread erzeugen<br />
! pthread_join Synchronisieren mehrerer <strong>Threads</strong><br />
! pthread_mutex_init Mutexvariable erzeugen <strong>und</strong> mit<br />
! Defaultwert initialisieren<br />
! pthread_mutex_lock Mutex locken vor broadcast<br />
! pthread_mutex_unlock Mutex unlocken nach broadcast<br />
! pthread_setschedparam Scheduling Verfahren <strong>und</strong> Priorität<br />
! für einen Thread festlegen<br />
!<br />
!D-<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 38
Posix Thread Beispiel – 3<br />
Datendeklaration<br />
INCLUDE 'GEN_INCL:ST(P<strong>Threads</strong>)'<br />
EXTERNAL Test_Thread1<br />
EXTERNAL TestF_Thread2<br />
EXTERNAL Test_Thread3<br />
PARAMETER PTHREAD_MUTEX_DEFAULT = 0<br />
PARAMETER anzworkers = 4<br />
INTEGER *4 ThrCount , SchedNr<br />
INTEGER *4 INDX , IStatus<br />
INTEGER *4 ThreadStackSize /819200/<br />
!size_t<br />
INTEGER *4 exitval<br />
RECORD /pthread_mutex_t/ SlowMutex, WeckMutex, CountMutex,<br />
RECORD /pthread_cond_t/ WeckCond, CountCond<br />
COMMON /COM_<strong>Threads</strong>/ SlowMutex, WeckMutex, CountMutex, WeckCond,<br />
1 CountCond, ThrCount<br />
REAL *4 x /1.0/<br />
RECORD /pthread_t/ Worker (anzworkers)<br />
RECORD /pthread_t/ Thread2<br />
RECORD /pthread_t/ Thread3<br />
RECORD /pthread_attr_t/s_gl_pthread_attr<br />
RECORD /pthread_attr_t/s_gl_pthread_attr2<br />
RECORD /sched_param/schedparam<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 39
Posix Thread Beispiel – 4<br />
<strong>Threads</strong> erzeugen<br />
ThrCount = 0<br />
schedparam.sched_priority = 9 !PRI_FG_MIN_NP 8 - 15!<br />
CALL pthread_mutex_init(CountMutex,%VAL(PTHREAD_MUTEX_DEFAULT))<br />
CALL pthread_mutex_init(WeckMutex,%VAL(PTHREAD_MUTEX_DEFAULT))<br />
! Thread Condition Varibale initialisieren<br />
IStatus = pthread_cond_init(WeckCond, )<br />
IStatus = pthread_cond_init(CountCond,)<br />
IStatus = pthread_attr_init(s_gl_pthread_attr)<br />
IStatus = pthread_attr_init(s_gl_pthread_attr2)<br />
IStatus = pthread_attr_setstacksize(s_gl_pthread_attr, ThreadStackSize)<br />
IStatus = pthread_attr_setstacksize(s_gl_pthread_attr2, ThreadStackSize)<br />
DO INDX = 1,anzworkers<br />
! Eine Prozedur mehrmals als Thread erzeugen (anzworkers)<br />
IStatus = pthread_create(Worker(INDX), %VAL(PTHREAD_CREATE_JOINABLE),<br />
1 test_thread1, %VAL(Indx))<br />
ENDDO<br />
IStatus = pthread_create(Thread2, %VAL(PTHREAD_CREATE_JOINABLE), test_thread2, %VAL(anzworker+1))<br />
IStatus = pthread_create(Thread3, %VAL(PTHREAD_CREATE_JOINABLE), test_thread3, %VAL(anzworker+2))<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 40
Posix Thread Beispiel – 5<br />
benachrichten <strong>und</strong> beenden<br />
!<br />
! Prioritäten der <strong>Threads</strong> festlegen<br />
!<br />
IStatus = pthread_setschedparam (%VAL(Thread3.Pointer), %VAL(Sched_Other), schedparam)<br />
!<br />
! Mittels Broadcast alle <strong>Threads</strong> der Variante Worker wecken<br />
!<br />
IStatus = pthread_cond_broadcast (%REF(WeckCond))<br />
PRINT*,'alle <strong>Threads</strong> aktiviert, Main wartet noch auf Rückmeldung '<br />
!<br />
! Mittels Signal Thread2 wecken<br />
!<br />
IStatus = pthread_cond_signal(%REF(CountCond))<br />
!<br />
! Ende aller <strong>Threads</strong> abwarten/oder herbeiführen<br />
!<br />
DO INDX = 1, anzworkers<br />
IStatus = pthread_join32(%VAL(Worker(INDX).Pointer),exitval)<br />
ENDDO<br />
IStatus = pthread_join32(%VAL(Thread3.Pointer),exitval)<br />
IStatus = pthread_cancel (%VAL(Thread2.Pointer))<br />
IStatus = pthread_join32(%VAL(Thread2.Pointer),exitval)<br />
END<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 41
Posix Thread Beispiel – 6<br />
test_Thread1,arbeitet periodisch, terminiert selbst<br />
SUBROUTINE test_thread1(thrnum)<br />
IMPLICIT NONE<br />
!<br />
! Thread wird mehrfach (Anzahl= anzworkers), konkurrierend in MAIN erzeugt<br />
! <strong>und</strong> mittels Broadcast geweckt.<br />
!<br />
! Verwendete Prozeduren:<br />
!<br />
! pthread_cond_wait Warten auf Ereignis <strong>und</strong> aufwachen des <strong>Threads</strong> mit Mutex<br />
! pthread_cond_timedwait Warten auf Ereignis mit Timeout (verwendbar als Timer bei <strong>Threads</strong>)<br />
! pthread_get_expiration_np Bestimmung der Ablaufzeit des Timers indem zur Systemzeit ein<br />
! Delta in Sek<strong>und</strong>en addiert wird<br />
! pthread_mutex_lock WeckMutex locken für pthreadcond_wait<br />
!<br />
INCLUDE 'GEN_INCL:ST(P<strong>Threads</strong>)'<br />
INTEGER<br />
*4 ThrCount<br />
RECORD<br />
/pthread_mutex_t/ SlowMutex<br />
RECORD<br />
/pthread_mutex_t/ WeckMutex<br />
RECORD<br />
/pthread_mutex_t/ CountMutex<br />
RECORD<br />
/pthread_cond_t/ WeckCond<br />
RECORD<br />
/pthread_cond_t/ CountCond<br />
COMMON /COM_<strong>Threads</strong>/ SlowMutex, WeckMutex, CountMutex, WeckCond,<br />
1 CountCond, ThrCount<br />
CHARACTER * 8 CTime<br />
INTEGER *4 a , thrnum, Error, INDX /0/, IStatus<br />
RECORD /PThread_TimeSpec_T/ WaitTime, ResWaitTime<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 42
Posix Thread Beispiel – 7<br />
test_Thread1,arbeitet periodisch, terminiert selbst<br />
CALL TIME (CTime)<br />
a = %LOC(thrnum)<br />
PRINT *, a,%LOC(a), ' thread ',a,' gestartet um:',CTime,%LOC(CTime), %LOC(WaitTime.tv_sec)<br />
WaitTime.tv_sec = 4<br />
WaitTime.tv_nsec = 0<br />
! Synchronisierung der <strong>Threads</strong> mit dem Hauptprogramm mittels einer<br />
! Condition Variablen<br />
IStatus = pthread_mutex_lock(WeckMutex)<br />
IStatus = pthread_cond_wait(WeckCond, WeckMutex)<br />
IStatus = pthread_mutex_unlock (WeckMutex)<br />
!<br />
! Timer definieren<br />
!<br />
IStatus = pthread_get_expiration_np (%REF(waittime),%REF(reswaittime))<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 43
Posix Thread Beispiel – 8<br />
test_Thread1,arbeitet periodisch, terminiert selbst<br />
DO INDX = 1,4<br />
IStatus = pthread_mutex_lock(CountMutex)<br />
thrCount = thrCount + 1<br />
IStatus = pthread_mutex_unlock(CountMutex)<br />
IStatus = pthread_mutex_lock (WeckMutex)<br />
IStatus = pthread_cond_timedwait(WeckCond, WeckMutex, reswaittime)<br />
Error = pthread_mutex_unlock (WeckMutex)<br />
CALL TIME (CTime)<br />
IF (IStatus .EQ. 0)THEN<br />
PRINT*,a,%LOC(a),' ', IStatus,' über Mutex/Condition rausgekommen'<br />
ELSEIF (IStatus .EQ. ETIMEDOUT) THEN<br />
PRINT*,a,%LOC(a),' Timer abgelaufen thread ',a,' Lauf:',INDX,' ',CTime<br />
ELSE<br />
PRINT*,a,%LOC(a),' Ende von Condition Wait Lauf ',INDX,' um',CTime,' Fehler ', IStatus<br />
ENDIF<br />
IStatus = pthread_get_expiration_np (%REF(waittime),%REF(reswaittime))<br />
IStatus = pthread_cond_signal(CountCond) ! Signal an einen anderen Thread, einen anderen Thread anstoßen<br />
ENDDO<br />
PRINT*,a,%LOC(a), ' Fertig....thread',a<br />
RETURN<br />
END<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 44
Posix Thread Beispiel – 9<br />
Endlos Thread, wird von main gestoppt<br />
SUBROUTINE test_thread2(thrnum)<br />
IMPLICIT NONE<br />
!<br />
! Endlos-Thread sitzt in ConditionWait <strong>und</strong> wird von anderen <strong>Threads</strong><br />
! via SIGNAL geweckt um dann irgendeinen Unsinn zu machen<br />
! Zusätzlich: Sperren <strong>und</strong> Freigeben einer globalen Variablen mittels<br />
! Mutex Lock <strong>und</strong> Unlock<br />
! Beenden des Endlos-<strong>Threads</strong> via PTHREAD_CANCEL in MAIN<br />
!<br />
! Verwendete Prozeduren:<br />
!<br />
! pthread_mutex_init Initialisierung der Mutexvariablen<br />
! für pthread_cond_wait<br />
! pthread_cond_wait Aufwachen des <strong>Threads</strong> mit Mutex<br />
! pthread_mutex_lock WeckMutex locken für pthread_cond_wait<br />
! pthread_mutex_unlock WeckMutex freigeben nach<br />
! pthread_cond_wait<br />
INCLUDE 'GEN_INCL:ST(P<strong>Threads</strong>)'<br />
INTEGER<br />
*4 ThrCount<br />
RECORD<br />
/pthread_mutex_t/ SlowMutex<br />
RECORD<br />
/pthread_mutex_t/ WeckMutex<br />
RECORD<br />
/pthread_mutex_t/ CountMutex<br />
RECORD<br />
/pthread_cond_t/ WeckCond<br />
RECORD<br />
/pthread_cond_t/ CountCond<br />
COMMON /COM_<strong>Threads</strong>/ SlowMutex, WeckMutex, CountMutex, WeckCond,<br />
1 CountCond, ThrCount<br />
RECORD<br />
Dienstag, 30. April<br />
2013<br />
/pthread_mutex_t/ WaitMutex<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 45
Posix Thread Beispiel – 10<br />
Endlos Thread, wird von main gestoppt<br />
CHARACTER * 8 CTime<br />
REAL *4 count /3.0/, x, y<br />
INTEGER *4 a, thrnum, I, IStatus<br />
IStatus = pthread_mutex_init(WaitMutex,)<br />
a = %LOC(thrnum)<br />
IStatus = 0<br />
DO WHILE (IStatus .EQ. 0)<br />
x = SIN(count)<br />
Count = Count + 1<br />
CALL Time (CTime)<br />
IStatus = pthread_mutex_lock(WaitMutex)<br />
IStatus = pthread_cond_wait(CountCond, WaitMutex)<br />
IStatus = pthread_mutex_unlock(WaitMutex)<br />
! Bereich der globalen Variablen thrcount schuetzen<br />
IStatus = pthread_mutex_lock(CountMutex)<br />
thrCount = INT(Count) + 1<br />
DO I =2,3<br />
y = y+(y*(i+1)/(i-1))<br />
ENDDO<br />
PRINT*,a,' y in Thread Typ 2',y<br />
PRINT*,a,' Absolute Anzahl in Thread Typ 2 ',thrcount<br />
IStatus = pthread_mutex_unlock(CountMutex)<br />
ENDDO<br />
RETURN<br />
END<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 46
Posix Thread Beispiel – 11<br />
test_thread3 - 1<br />
SUBROUTINE test_thread3 (thrnum)<br />
IMPLICIT NONE<br />
!<br />
! Thread wird in MAIN gestartet <strong>und</strong> führt Berechnungen mit<br />
! vielen Iterationsschritten durch. Getestet (demontriert) wird die<br />
! Prioriätssteuerung (Scheduling) dieses <strong>Threads</strong> im Verhältnis<br />
! zu den konkurrierenden <strong>Threads</strong>.<br />
!<br />
INCLUDE 'GEN_INCL:ST(P<strong>Threads</strong>)'<br />
LOGICAL *4 Thread_Hold<br />
INTEGER<br />
*4 ThrCount<br />
RECORD<br />
/pthread_mutex_t/ SlowMutex<br />
RECORD<br />
/pthread_mutex_t/ WeckMutex<br />
RECORD<br />
/pthread_mutex_t/ CountMutex<br />
RECORD<br />
/pthread_cond_t/ WeckCond<br />
RECORD<br />
/pthread_cond_t/ CountCond<br />
COMMON /COM_<strong>Threads</strong>/ SlowMutex, WeckMutex, CountMutex, WeckCond,<br />
1 CountCond, ThrCount<br />
CHARACTER *8 CTime<br />
REAL *4 x<br />
REAL *4 y /1.0/<br />
INTEGER<br />
*4 a<br />
INTEGER *4 count1 /1/<br />
INTEGER *4 count /3/<br />
INTEGER<br />
*4 I<br />
INTEGER<br />
*4 thrnum<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 47
Posix Thread Beispiel – 12<br />
test_thread3 - 2<br />
a = %LOC(thrnum)<br />
CALL TIME (CTime)<br />
PRINT *, a,' thread ',a,' gestartet um:',CTime<br />
DO count = 1, 999999<br />
y = 1.0<br />
x = sin(float(count))<br />
DO I =3, 5<br />
y = y+(y*(i+1)/(i))<br />
ENDDO<br />
IF(MOD (count,10000) .EQ. 0) THEN<br />
PRINT*,a,' x = sin(float(count))',x,' count ',count<br />
PRINT*,a,' y in Thread Typ 3 ',y<br />
ENDIF<br />
ENDDO<br />
PRINT*,a,' y in Thread Typ 3 ',y<br />
PRINT*,a,' Fertig!..thread ',a<br />
RETURN<br />
END<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 48
Singlethread-Programme multithreadfähig<br />
machen (1)<br />
Konflikte zwischen <strong>Threads</strong> beim Gebrauch globaler Variablen<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 49
Singlethread-Programme multithreadfähig<br />
machen (2)<br />
<strong>Threads</strong> können private globale Variablen haben<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 50
Interprozesskommunikation IPC<br />
• Weil <strong>Prozesse</strong> vom Betriebssystem gegenseitig von<br />
einander geschützt werden (Speicherschutz !), braucht<br />
man eine Interprozesskommunikationen, falls <strong>Prozesse</strong><br />
untereinander kommunizieren, aufeinander warten oder<br />
Daten <strong>und</strong> Ressourcen austauschen müssen.<br />
• Typische Fälle dafür sind:<br />
– Mehrere <strong>Prozesse</strong> müssen spezielle Daten gemeinsam verwenden.<br />
– Die <strong>Prozesse</strong> sind untereinander abhängig <strong>und</strong> müssen aufeinander<br />
warten.<br />
– Daten müssen von einem Prozess zu einem anderen weitergereicht<br />
werden.<br />
– Die Verwendung von Systemressourcen muss koordiniert werden<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 51
IPC – Techniken unter Linux<br />
Entnommen dem openbook von Galileo unter:<br />
http://openbook.galileocomputing.de/linux_unix_programmierung/Kap09-<br />
000.htm#RxxKap09000040002B71F02D10D<br />
• Namenlose Pipes<br />
• Benannte Pipes (FIFO Pipes)<br />
• Message Queue (Nachrichtenspeicher)<br />
• Semaphore<br />
• Shared Memory (gemeinsamer Speicher)<br />
• STREAMS<br />
• Sockets<br />
• Lock Files (Sperrdateien)<br />
• Datei Sperren (Record Locking)<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 52
IPC – Techniken unter Linux<br />
Namenlose Pipes<br />
• Pipes, wie auch FIFOs (named Pipes), sind die einzigen<br />
beiden IPCs, die garantiert auf jedem System vorhanden<br />
sind.<br />
• Eine Pipe ist ein unidirektionaler Kommunikationskanal<br />
zwischen zwei verwandten <strong>Prozesse</strong>n<br />
• $ ps ax | less startet in der Shell zwei <strong>Prozesse</strong>. Einer führt das<br />
Kommando ps ax aus <strong>und</strong> schreibt das Ergebnis an die<br />
Standardausgabe. Durch die Pipe (|) wird allerdings diese<br />
Standardausgabe an den Prozess less weitergeleitet. less liest hierbei<br />
die Daten von der Standardeingabe ein <strong>und</strong> gibt aus, was ihm das<br />
Kommando ps durch die Pipe zuschickt<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 53
IPC – Techniken unter Linux -Pipes<br />
• Wenn Daten in beide Richtungen ausgetauscht werden,<br />
muss eine zweite Pipe dazu verwendet werden. Eine Pipe ist<br />
wie ein Rohr, wo Daten in die eine Seite (Prozess A)<br />
hineingesteckt werden <strong>und</strong> bei Prozess B wieder<br />
herauskommen.<br />
• Eine Pipe dient außer zur Kommunikation zwischen zwei<br />
<strong>Prozesse</strong>n zur Flusskontrolle, weil eine Pipe nur eine<br />
bestimmte Menge an Daten aufnehmen kann. Ist die Pipe<br />
voll, wird ein Prozess mindestens so lange angehalten, bis<br />
mindestens ein Byte aus der vollen Pipe gelesen wurde <strong>und</strong><br />
Platz vorhanden ist, um die Pipe wieder mit Daten zu<br />
befüllen. Andersherum: ist die Pipe leer, wird der lesende<br />
Prozess so lange angehalten, bis der schreibende Prozess<br />
etwas in diese Pipe schickt.<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 54
IPC – Techniken unter Linux -Pipes<br />
• Es gibt also eine Schreibseite <strong>und</strong> eine Leseseite bei einer<br />
Pipe. Somit ist also nur eine Kommunikation in einer<br />
Richtung möglich (half-duplex):<br />
Eigenschaften von elementaren E/A-Funktionen bei Pipes<br />
• read() – liest Daten vom Ende des Puffers der Pipe, entweder<br />
– synchron (blockierend), bis sich genügend Daten in der Pipe befinden. Schreibt kein Prozess in<br />
die Pipe, blockiert read() so lange, bis der schreibende Prozess den Systemaufruf close() aufruft.<br />
Dieses Blockieren von read() eignet sich zum Synchronisieren von <strong>Prozesse</strong>n.<br />
oder<br />
– asynchron (nicht blockierend) , indem mit der Funktion fcntl() das Flag O_NONBLOCK oder<br />
O_NDELAY gesetzt wird. Ist die Pipe fürs Schreiben geöffnet worden, aber momentan leer,<br />
liefert read() 0 (nicht EOF) zurück<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 55
IPC – Techniken unter Linux -Pipes<br />
• write() schreibt die Daten immer ans Ende des Pipe-Puffers, entweder .<br />
– synchron (blockierend): Ist die Pipe voll, wird der schreibende Prozess so lange blockiert, bis<br />
wieder genügend Platz zum Schreiben vorhanden ist<br />
oder<br />
– asynchron (nicht blockierend), indem mit der Funktion fcntl() das Flag O_NONBLOCK oder<br />
O_NDELAY gesetzt wird. Bei vollem Puffer liefert der schreibende Prozess 0 zurück..<br />
• Meistens betreibt man eine Pipe blockierend. Ein Schreiben innerhalb der<br />
PIPE_BUF-Grenze ist atomar, kein anderer Prozess kann dieses Schreiben<br />
unterbrechen <strong>und</strong> selbst in die Pipe schreiben. Versucht ein Prozess, in eine Pipe<br />
zu schreiben, die noch von keinem anderen Prozess zum Lesen geöffnet wurde,<br />
wird dem Prozess das Signal SIGPIPE (broken pipe) gesendet, was standardmäßig<br />
den Abbruch des schreibenden <strong>Prozesse</strong>s bedeutet.<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 56
IPC – Techniken unter Linux<br />
Benannte Pipes<br />
• Mit Pipes können nur miteinander verwandte <strong>Prozesse</strong> (fork())<br />
kommunizieren. Mit FIFOs (benannten Pipes) kann man mit einem<br />
völlig fremden Prozess kommunizieren, da solche Pipes über einen<br />
Dateinamen angesprochen werden können.<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 57
IPC – Techniken unter Linux<br />
Benannte Pipes - ein Beispiel<br />
• Auf der Shell lässt sich ein FIFO folgendermaßen erstellen:<br />
• $ mkfifo fifo1 Bei einem Blick ins aktuelle Arbeitsverzeichnis finden Sie das FIFO unter<br />
folgendem Eintrag:<br />
• $ ls -l prw-r--r-- 1 tot users 0 2003–12–07 10:53 fifo1<br />
• Am p am Anfang erkennen Sie das FIFO. Sie könnten jetzt etwas in das FIFO schreiben:<br />
• [tty1]<br />
• $ echo Der erste Eintrag in das FIFO > fifo1<br />
• [tty2]<br />
• $ echo Der zweite Eintrag in das FIFO > fifo1<br />
• Beide Dialogstationen blockieren im Augenblick <strong>und</strong> warten, bis die Daten im FIFO<br />
ausgelesen werden. Wir öffnen eine dritte Konsole <strong>und</strong> lesen ihn aus:<br />
• [tty3]<br />
• $ cat fifo1<br />
• Der zweite Eintrag in das FIFO<br />
• Der erste Eintrag in das FIFO<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 58
IPC – Techniken unter Linux<br />
Benannte Pipes - Kommunikationsmodell eines FIFO (First<br />
In - First Out)<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 59
IPC – Techniken unter Linux<br />
Message Queue (Nachrichtenspeicher) ist ein<br />
Mechanismus zum Austausch von Nachrichten zwischen<br />
<strong>Prozesse</strong>n. Die Nachrichten werden dabei von einem Prozess<br />
an einen Speicher (der Message Queue = Nachrichtenschlange)<br />
geschickt <strong>und</strong> können dort von einem anderen<br />
Prozess abgeholt werden.<br />
• Größe <strong>und</strong> Anzahl der Nachrichten werden vom System festgelegt.<br />
• Die Nachricht selbst besteht aus einem Text <strong>und</strong> einem Nachrichtentyp.<br />
• Die Nachrichten werden in der Reihenfolge, in der diese eintreffen, auch<br />
wieder ausgelesen.<br />
• Fordert ein Prozess eine Nachricht an, so kann über eine Option angegeben<br />
werden, dass dieser entweder so lange angehalten wird, bis eine Nachricht<br />
eingeht, oder sofort zur Programmausführung zurückkehrt <strong>und</strong> eventuell einen<br />
Fehlercode ausgibt.<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 60
IPC – Techniken unter Linux<br />
Message Queue<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 61
IPC – Techniken unter Linux<br />
Shared Memory<br />
• Mehrere <strong>Prozesse</strong> können auf einen gemeinsamen<br />
Datenspeicherbereich zugreifen.<br />
1. Ein Prozess muss diesen gemeinsamen Datenspeicher anlegen.<br />
2. <strong>Prozesse</strong>, die ebenfalls darauf zugreifen sollen, werden mit diesem<br />
Datenspeicher bekannt gemacht, indem der Speicherbereich im Adressraum<br />
der entsprechenden <strong>Prozesse</strong> eingefügt wird. Ebenfalls muss hierbei den<br />
<strong>Prozesse</strong>n mitgeteilt werden, wie diese auf den Speicherbereich zugreifen<br />
können (lesend/schreibend).<br />
• Leider wurde mit dem Shared Memory IPC keine explizite<br />
Synchronisation zur Verfügung gestellt, weshalb man<br />
diese Kontrolle selbst noch mit z. B. Sperren oder<br />
Semaphoren herstellen muss.<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 62
IPC – Techniken unter Linux<br />
Sockets<br />
• Sockets wurden im Berkeley-UNIX-System (BSD) als<br />
Kommunikation zwischen <strong>Prozesse</strong>n auf verschiedenen<br />
Rechnern über ein Netzwerk eingeführt. Sockets können<br />
zur Kommunikation verschiedenste Protokolle benutzen, z.<br />
B. TCP/IP, UDP/IP oder UNIX Domain Sockets.<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 63
Interprozess Kommunikation IPC<br />
Race Conditions – Wettlaufsituationen<br />
Was passiert, wenn zwei <strong>Prozesse</strong> auf gemeinsam genutzten<br />
Speicher gleichzeitig zugreifen wollen? Beispiel<br />
Druckerspooler<br />
Prozess A liest in = 7<br />
A wird unterbrochen<br />
Prozess B liest in = 7<br />
B trägt Dateinamen an<br />
Stelle 7 <strong>und</strong> aktualisiert<br />
in auf 8<br />
A wird aktiviert <strong>und</strong> trägt<br />
ebenfalls den<br />
Dateinamen auf Stelle 7.<br />
Datei von B wird nicht<br />
gedruckt<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 64
IPC - Race Conditions –Wettlaufsituationen<br />
• Situationen, in denen zwei oder mehr <strong>Prozesse</strong> einen<br />
gemeinsamen Speicher lesen oder beschreiben <strong>und</strong> das<br />
Endergebnis davon abhängt, wer wann genau läuft,<br />
werden Race Conditions genannt.<br />
• Programme, die Race Conditions enthalten, zu<br />
debuggen, macht keinen Spaß, weil Abläufe nicht<br />
reproduzierbar sind. Sie müssen vermieden werden!<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 65
IPC - Kritische Abschnitte (1)<br />
Die Teile des Programms, in denen auf gemeinsam<br />
genutzten Speicher (Resourcen) zugegriffen wird,<br />
nennt man kritische Region oder kritischer Abschnitt<br />
• Keine zwei <strong>Prozesse</strong> dürfen gleichzeitig in ihren<br />
kritischen Bereichen sein<br />
• Es dürfen keine Annahmen über Anzahl <strong>und</strong><br />
Geschwindigkeiten von CPUs gemacht werden<br />
• Kein Prozess, der außerhalb seines kritischen Bereichs<br />
läuft, darf andere <strong>Prozesse</strong> blockieren<br />
• Kein Prozess sollte ewig darauf warten müssen, in seine<br />
kritische Region einzutreten<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 66
IPC - Kritische Abschnitte (2)<br />
• Wechselseitiger Ausschluss (Mutual exclusion) unter<br />
Verwendung von kritischen Regionen<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 67
IPC - Wechselseitiger Ausschluss durch aktives<br />
Warten - Unterbrechungen ausschalten<br />
Einfachste Möglichkeit:<br />
jeder Prozess kann die Interruptbehandlung im Prozessor<br />
ausschalten, wenn er in seinen kritischen Bereich eintritt.<br />
-> Schedular kann Prozess nicht unterbrechen – keine<br />
Raceconditions - Problem gelöst !<br />
Aber: Was ist , wenn der Prozess nachher die Interruptbehandlung<br />
nicht wieder aktiviert?<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 68
IPC - Wechselseitiger Ausschluss durch<br />
aktives Warten - Variablen sperren<br />
Softwarelösung:<br />
es wird eine gemeinsame Sperrvariable (SV) beutzt. Ist SV 0, darf<br />
ein Prozess den Bereich betreten, zuvor setzt er SV 1.<br />
Notwendige Schritte:<br />
1. SV aus dem Speicher laden<br />
2. SV auf null testen<br />
3. wenn nicht, weiter bei 1.<br />
4. SV auf 1 setzten<br />
5. kritischen Bereich betreten<br />
Angenommen, SV = 0. Was passiert, wenn der Scedular P1 im<br />
Schritt 2 unterbricht <strong>und</strong> P2 mit Schritt eins beginnt ?<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 69
IPC - Wechselseitiger Ausschluss durch<br />
aktives Warten - Strikter Wechsel<br />
(a) Process 0. (b) Process 1.<br />
a betritt, wenn turn = 0 b betritt, wenn turn = 1<br />
"Kein Prozess, der außerhalb seines kritischen Bereichs<br />
läuft, darf andere <strong>Prozesse</strong> blockieren" kann hier<br />
verletzt werden !<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 70
IPC - Wechselseitiger Ausschluss durch<br />
aktives Warten - Petersons Lösung<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 71
IPC - Wechselseitiger Ausschluss durch<br />
aktives Warten - Petersons Lösung<br />
Angenommen, beide <strong>Prozesse</strong> rufen enter_region beinahe<br />
gleichzeitig auf:<br />
Beide speichern ihre Prozessnummern in turn<br />
Wer zuletzt kam gewinnt. Das erste Ergebnis geht verloren.<br />
z.B. turn = 1: Wenn beide <strong>Prozesse</strong> zur while Schleife kommen,<br />
führt sie Prozess 0 null mal aus <strong>und</strong> betritt die kritische Region.<br />
Prozess 1 geht in die Schleife <strong>und</strong> betritt seine kritische Region so<br />
lange nicht, bis Prozess 0 seine kritische Region verlässt.<br />
Petersons Lösung für wechselseitigen<br />
Ausschluss<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 72
IPC - Wechselseitiger Ausschluss durch<br />
aktives Warten - TSL Anweisung<br />
Eintreten <strong>und</strong> Verlassen der kritischen Region unter<br />
Verwendung der TSL Anweisung<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 73
IPC - Wechselseitiger Ausschluss durch<br />
aktives Warten - Nachteile<br />
Nachteile des aktiven Wartens:<br />
• Warten verbraucht CPU Zeit<br />
• Ist ein Process mit sehr hoher Priorität in enter_region, kommt er aus der<br />
while Schleife nicht mehr heraus, wenn ein Prozess mit sehr niedriger<br />
Priorität in leave_region einfach nie dran kommt<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 74
IPC - Sleep and Wakeup Erzeuger-<br />
Verbraucher Problem<br />
Zwei <strong>Prozesse</strong> benutzen einen<br />
gemeisamen allgemeinen Puffer<br />
mit fester Größe. Der Erzeuger<br />
legt Informationen hinein, der<br />
Verbraucher nimmt sie heraus.<br />
Synchronisation ist notwendig<br />
bei Aufruf von sleep blockiert<br />
der Schedular den thread<br />
nach Aufruf von wakeup setzt<br />
ihn der Schedular wieder auf<br />
laufbereit<br />
Dienstag, 30. April<br />
2013<br />
Erzeuger-Verbraucher Problem<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 75
IPC - Sleep and Wakeup - Ermitteln Sie die<br />
Race Condition !<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 76
IPC-Sleep and Wakeup –Race Condition<br />
Beispiel:<br />
1. Puffer ist leer<br />
2. consumer hat gerade count gelesen<br />
(= = 0) <strong>und</strong> will sleep aufrufen.<br />
3. Schedular unterbricht consumer<br />
4. Schedular startet producer<br />
5. producer fügt Nachricht ein, erhöht<br />
count um 1<br />
6. producer merkt, dass count = 1 ist<br />
<strong>und</strong> weckt den consumer, der<br />
offensichtlich schlafen muss.<br />
consumer schläft aber noch gar<br />
nicht, Weckruf geht verloren.<br />
7. Schedular startet wieder consumer<br />
8. consumer prüft den count, den er<br />
vorher gelesen hat (==0) <strong>und</strong> geht<br />
schlafen<br />
9. Irgendwann erzeugt der producer<br />
neuen Eintrag <strong>und</strong> geht auch<br />
Problem ist nur, dass ein Wecksignal verloren gehen kann! schlafen.<br />
Dienstag, 30. April<br />
Betriebssysteme <strong>und</strong> nebenläufige 10. Jetzt schlafen beide für immer !<br />
2013<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 77
IPC - Semaphoren : Erzeuger-Verbraucher Problem<br />
‣ Die down Operation eines<br />
Semaphors prüft, ob der Wert<br />
größer 0 ist.<br />
‣ S > 0, down erniedrigt den<br />
Wert um eins (z.B. um einen<br />
gespeicherten Weckruf zu<br />
verbrauchen) <strong>und</strong> macht<br />
einfach weiter<br />
‣ S = 0, Prozess oder Thread<br />
wird sofort schlafen gelegt<br />
‣ down ist atomare (nicht<br />
unterbrechbare) Operation <strong>und</strong><br />
verhindert deshalb Race Conditions<br />
‣ up <strong>und</strong> down werden in der Regel<br />
als Systemaufrufe realisiert, bei<br />
denen das BS alle Unterbrechungen<br />
ausschaltet, solange es die<br />
Semaphore überprüft, sie<br />
aktualisiert <strong>und</strong> den Prozess ggf.<br />
schlafen legt<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 78
IPC Semaphoren : Erzeuger-Verbraucher Problem<br />
‣ Die up Operation erhöht den Wert<br />
um eins<br />
‣ gibt es schlafende <strong>Prozesse</strong> ( in der<br />
Operation down) wird einer von<br />
ihnen geweckt, dekrementiert das<br />
Semaphore wieder auf 0 <strong>und</strong><br />
kommt aus dem down zurück.<br />
‣ Somit bleibt nach einem up an ein<br />
Semaphore, auf das schlafende<br />
<strong>Prozesse</strong> warten, der Wert des<br />
Semaphores immer noch auf 0, aber<br />
es gibt einen Prozess weniger, der<br />
wegen des Semaphores schläft.<br />
‣ up ist ebenfalls eine atomare<br />
Operation<br />
.<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 79
IPC - Semaphoren<br />
‣ Die Mutex Semaphoren werden für<br />
gegenseitigen Ausschluss verwendet.<br />
‣ Sie schützen den Puffer vor<br />
gleichzeitigem Lesen <strong>und</strong> Schreiben.<br />
‣ Full <strong>und</strong> empty sind Synchronisationssemaphoren.<br />
‣ Empty hält den producer an, wenn der<br />
Puffer voll ist.<br />
‣ Full hält den Verbraucher an, wenn der<br />
Puffer leer ist<br />
‣ kein wechselseitiger Ausschluss !<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 80
IPC - Mutexes<br />
Realisierung von mutex_lock <strong>und</strong> mutex_unlock<br />
‣ vereinfachte Semaphore (kann nicht zählen, binäre Semaphore)<br />
‣ dient dem gegenseitigen Ausschluss, Schutz für kritischen Bereich<br />
‣ Ähnlich wie Folie Wechselseitiger Ausschluss durch aktives Warten (5) aber:<br />
thread_yield gibt die CPU wieder frei, kein aktives Warten<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 81
IPC - Probleme mit Semaphoren<br />
Dienstag, 30. April<br />
2013<br />
Angenommen im Code des producer steht:<br />
down (&mutex);<br />
down (&empty);<br />
insert_item(item);<br />
...<br />
Angenommen: der consumer läuft nicht<br />
dann: producer betritt 100 mal den<br />
kritischen Bereich, dekrementiert empty<br />
auf null <strong>und</strong> geht deshalb im kritischen<br />
Bereich schlafen.<br />
Jetzt kommt der consumer <strong>und</strong> kann den<br />
kritischen Bereich nicht betreten, legt sich<br />
auch schlafen<br />
Producer wartet auf up(&empty) des<br />
consumers <strong>und</strong> der consumer wartet auf<br />
up(&mutex) des producers.<br />
Klassischer Fall eines Deadlock<br />
Programmierfehler können leicht passieren<br />
Deshalb Monitore!<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 82
IPC - Monitor (1)<br />
‣ Realisiert ein höherstufiges Synchronisationsprinzip<br />
als Semaphore<br />
‣ Ist eine Sammlung von Prozeduren, Variablen <strong>und</strong><br />
Datenstrukturen.<br />
‣ Prozeduren können aufgerufen, deren Variablen<br />
aber nicht von außen geändert werden<br />
‣ Definitionsgemäß darf <strong>und</strong> kann immer nur ein<br />
Prozess im Monitor aktiv sein<br />
‣ Monitor ist ein Programmiersprachenkonstrukt, das<br />
der Compiler speziell behandlen kann<br />
‣ Der Compiler (nicht der Programmierer) realisiert<br />
den wechselseitigen Ausschluß<br />
Beispiel eines Monitors in Pidgin Pascal<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 83
IPC - Monitor (2)<br />
• Outline of producer-consumer problem with monitors<br />
only one monitor procedure active at one time, buffer has N slots<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 84
IPC - Monitors (3)<br />
Solution to producer-consumer problem in Java (part 1)<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 85
IPC - Monitors (4)<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 86
IPC – Möglichkeiten<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 87
Message Passing<br />
The producer-consumer problem with N messages<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 88
Barriers<br />
• Use of a barrier<br />
– processes approaching a barrier<br />
– all processes but one blocked at barrier<br />
– last process arrives, all are let through<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 89
Dining Philosophers (1)<br />
• Philosophers eat/think<br />
• Eating needs 2 forks<br />
• Pick one fork at a time<br />
• How to prevent deadlock<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 90
Dining Philosophers (2)<br />
A nonsolution to the dining philosophers problem<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 91
Dining Philosophers (3)<br />
Dienstag, 30. April<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Solution 2013 to dining Anwendugen philosophers - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> problem (part 1) 92
Dining Philosophers (4)<br />
Dienstag, 30. April<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Solution 2013 to dining Anwendugen philosophers - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> problem (part 2) 93
The Readers and Writers Problem<br />
A solution to the readers and writers problem<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 94
The Sleeping Barber Problem (1)<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 95
The Sleeping Barber Problem (2)<br />
Dienstag, 30. April<br />
2013<br />
Solution to sleeping barber problem.<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 96
Scheduling<br />
Introduction to Scheduling (1)<br />
• Bursts of CPU usage alternate with periods of I/O wait<br />
– a CPU-bo<strong>und</strong> process<br />
– an I/O bo<strong>und</strong> process<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 97
Introduction to Scheduling (2)<br />
Dienstag, 30. April<br />
2013<br />
Scheduling Algorithm Goals<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 98
Scheduling in Batch Systems (1)<br />
An example of shortest job first scheduling<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 99
Scheduling in Batch Systems (2)<br />
Dienstag, 30. April<br />
2013<br />
Three level scheduling<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 100
Scheduling in Interactive Systems (1)<br />
• Ro<strong>und</strong> Robin Scheduling<br />
– list of runnable processes<br />
– list of runnable processes after B uses up its quantum<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 101
Scheduling in Interactive Systems (2)<br />
A scheduling algorithm with four priority classes<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 102
Scheduling in Real-Time Systems<br />
Schedulable real-time system<br />
• Given<br />
– m periodic events<br />
– event i occurs within period P i and requires C i<br />
seconds<br />
• Then the load can only be handled if<br />
Dienstag, 30. April<br />
2013<br />
m<br />
<br />
i1<br />
C<br />
i<br />
P<br />
i<br />
<br />
1<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 103
Policy versus Mechanism<br />
• Separate what is allowed to be done with<br />
how it is done<br />
– a process knows which of its children threads<br />
are important and need priority<br />
• Scheduling algorithm parameterized<br />
– mechanism in the kernel<br />
• Parameters filled in by user processes<br />
– policy set by user process<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 104
Thread Scheduling (1)<br />
Possible scheduling of user-level threads<br />
• 50-msec process quantum<br />
• threads run 5 msec/CPU burst<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 105
Thread Scheduling (2)<br />
Possible scheduling of kernel-level threads<br />
• 50-msec process quantum<br />
• threads run 5 msec/CPU burst<br />
Dienstag, 30. April<br />
2013<br />
Betriebssysteme <strong>und</strong> nebenläufige<br />
Anwendugen - <strong>Prozesse</strong> <strong>und</strong> <strong>Threads</strong> 106