Prozess — Änderungen 11053 → 11508

Zeile 10: Zeile 10:
 
Ein Prozess kann dazu einen Kindprozess erzeugen, und diesem eine Aufgabe übergeben. Dieses Vorgehen ist zwar völlig legitim und würde funktionieren, hat jedoch zwei große Nachteile. Erstens gibt es bei einem Task Switch einen relativ großen Overhead, also wäre der Wechsel zwischen den Prozessen zu langsam, um damit sorglos umzugehen. Außerdem hängen die Prozesse womöglich relativ nah zusammen, sodass sie oft gemeinsame Daten brauchen. Sie müssten also durch verschiedene [[Interprozesskommunikation|Interprozesskommunikationsmethoden]] kommunizieren, was ebenfalls langsam sein kann.
 
Ein Prozess kann dazu einen Kindprozess erzeugen, und diesem eine Aufgabe übergeben. Dieses Vorgehen ist zwar völlig legitim und würde funktionieren, hat jedoch zwei große Nachteile. Erstens gibt es bei einem Task Switch einen relativ großen Overhead, also wäre der Wechsel zwischen den Prozessen zu langsam, um damit sorglos umzugehen. Außerdem hängen die Prozesse womöglich relativ nah zusammen, sodass sie oft gemeinsame Daten brauchen. Sie müssten also durch verschiedene [[Interprozesskommunikation|Interprozesskommunikationsmethoden]] kommunizieren, was ebenfalls langsam sein kann.
  
−
Als Lösung wurde das Prinzip des Threads (engl. für (Ausführungs-) Faden) entwickelt und in den Prozessbegriff integriert. Jeder Prozess hat mindestens einen Thread, der jeweils seinen eigenen Stack und Instruction Pointer hat. Jedoch teilen die Threads eines Prozesses sich die Daten, und können gleichberechtigt darauf zugreifen.
+
Als Lösung wurde das Prinzip des Threads (engl. für (Ausführungs-) Faden) entwickelt und in den Prozessbegriff integriert. Jeder Prozess hat mindestens einen Thread, der jeweils seinen eigenen Stack und Instruction Pointer hat. Alle Ressourcen (Dateihandles, Daten im Speicher, etc.) können von allen Threads benutzt werden, wodurch es aber auch zu Race Conditions (zwischen den einzelnen Threads) kommen kann.
 +
 
 +
Unabhängig von der Implementierung der Threads gibt es verschiedene Möglichkeiten diese dann zu benutzen. Im einfachsten Fall können direkt die Systemschnittstellen benutzt werden (bspw [[pthread]]s). Stattdessen ist es aber auch möglich darauf aufbauende, umfangreichere Schnittstellen zu nutzen, beispielsweise [http://openmp.org/wp/ OpenMP] für C/C++.
 +
 
 +
=== Implementierung von Threads ===
  
 
Für die Implementierung von Threads existieren im Großen und Ganzen zwei Prinzipien: Kernelthreads und Benutzerthreads. Außerdem können beide Verfahren noch kombiniert werden, sodass es noch die Möglichkeit eines hybriden Systems gibt.
 
Für die Implementierung von Threads existieren im Großen und Ganzen zwei Prinzipien: Kernelthreads und Benutzerthreads. Außerdem können beide Verfahren noch kombiniert werden, sodass es noch die Möglichkeit eines hybriden Systems gibt.
  
−
Ein Kernelthread ist dem Betriebssystem genauso bekannt wie ein Prozess, vielleicht bekommen sie sogar eine PID. Der Scheduler kann sie verwalten und Threads ihre Rechenzeit entziehen. [[Linux]] nutzt dieses Prinzip. Aufgrund ihrer Ähnlichkeit zu normalen Prozessen heißen sie dort auch ''light-weight processes'' (leichtgewichtige Prozesse, kurz: LWP).
+
Ein Kernelthread ist dem Betriebssystem genauso bekannt wie ein Prozess, vielleicht bekommen sie sogar eine PID. Der Scheduler kann sie verwalten und Threads ihre Rechenzeit entziehen. [[Linux]] nutzt dieses Prinzip. Aufgrund ihrer Ähnlichkeit zu normalen Prozessen heißen sie dort auch ''light-weight processes'' (leichtgewichtige Prozesse, kurz: LWP). Durch das Betriebssystem werden dem Userspace spezielle [[Systemaufruf]]e zum Erstellen und Zerstören von Threads bereitgestellt.
 +
 
 +
Bei Benutzerthreads sind die Voraussetzungen in den Programmen selbst enthalten (was nicht bedeutet, dass der Programmierer sie selbst implementieren muss, er kann einfach gegen eine Bibliothek linken). Ein solcher Prozess bekommt seine Rechenzeit zugeteilt, als hätte er gar keine Threads (denn der Scheduler weiß nichts von ihnen), und das Programm teilt diese unter ihren Threads auf. Es ist jedoch absolut notwendig, dass die Threads kooperieren, denn wenn ein Thread rechnet, dann rechnet er, und  das Threadsystem kann nicht selbstständig die Kontrolle erhalten, wie es der Kernel durch [[Interrupt|Interrupts]] tun würde.
  
−
Die Voraussetzungen für Benutzerthreads sind in den Programmen selbst enthalten (was nicht bedeutet, dass der Programmierer sie selbst implementieren muss, er kann einfach gegen eine Bibliothek linken). Ein solcher Prozess bekommt seine Rechenzeit zugeteilt, als hätte er gar keine Threads (denn der Scheduler weiß nichts von ihnen), und das Programm teilt diese unter ihren Threads auf. Es ist jedoch absolut notwendig, dass die Threads kooperieren, denn wenn ein Thread rechnet, dann rechnet er, und  das Threadsystem kann nicht selbstständig die Kontrolle erhalten, wie es der Kernel durch [[Interrupt|Interrupts]] tun würde.
+
Ebenfalls möglich wäre ein Hybridverfahren bei dem der Userspace-Prozess die eigenen Threads selber verwaltet, der Kernel aber unterstützt indem beim Scheduling an eine bestimmte Stelle gesprungen wird und nicht an die letzte. Dadurch könnte immer der Prozess-eigene Thread-Scheduler aktiviert werden und den richtigen nächsten Thread auswählen. Der Kernel müsste dem Thread-Scheduler dann irgendwie den letzten Prozess-Zustand übergeben, damit der gespeichert werden kann.
  
 
== Siehe auch ==
 
== Siehe auch ==