„Anwendungsebene“ bezieht sich auf die Laufzeitumgebung normaler Prozesse im Gegensatz zu Kernelprozessen. Das bedeutet nicht unbedingt, dass diese Prozesse tatsächlich von Benutzern gestartet wurden, da auf einem Standardsystem üblicherweise bereits mehrere „Daemon“-Prozesse laufen, bevor ein Benutzer überhaupt eine Sitzung eröffnet. Daemon-Prozesse sind Prozesse der Anwendungsebene.
Wenn der Kernel seine Initialisierungsphase beendet hat, startet er den ersten Prozess, init
. Prozess #1 ist für sich selbst kaum nützlich, und Unix-artige Systeme laufen mit allen möglichen Arten von Prozessen.
Zunächst einmal kann sich ein Prozess kopieren (dies wird als Fork bezeichnet). Der Kernel teilt einen neuen, aber gleichgroßen Prozess-Speicherplatz zu und einen weiteren Prozess, um ihn zu nutzen. Zu diesem Zeitpunkt besteht der einzige Unterschied zwischen den beiden Prozessen in ihrer PID. Der neue Prozess wird üblicherweise Kindprozess genannt, und der Prozess, dessen PID sich nicht ändert, Elternprozess.
Manchmal fährt der Kindprozess fort, sein eigenes Leben unabhängig vom Elternprozess zu führen, mit seinen eigenen, vom Elternprozess kopierten Daten. In vielen Fällen führt der Kindprozess jedoch ein anderes Programm aus. Bis auf wenige Ausnahmen wird sein Speicher einfach durch den Speicher des neuen Programms ersetzt, und die Ausführung dieses neuen Programms beginnt. Eine der ersten Aktionen von Prozess 1 besteht beispielsweise darin, sich zu verdoppeln (das heißt, dass es für eine winzige Zeitspanne zwei laufende Exemplare desselben
init
-Prozesses gibt), jedoch wird der Kindprozess dann durch das erste Systeminitialisierungsskript ersetzt, normalerweise durch
/etc/init.d/rcS
. Dieses Skript kopiert sich seinerseits und führt mehrere andere Programme aus. Zu einem bestimmten Zeitpunkt startet ein Prozess der
init
-Abkömmlinge dann eine grafische Schnittstelle, über die sich Benutzer anmelden können (der tatsächliche Ablauf der Ereignisse ist in größerer Ausführlichkeit in
Abschnitt 9.1, „Systemstart“ beschrieben.
Wenn ein Prozess die Aufgabe, für die er gestartet wurde, erfüllt hat, beendet er sich. Anschließend nimmt der Kernel den diesem Prozess zugewiesenen Speicher wieder zurück und hört auf, Teile der Prozessorzeit zuzuteilen. Der Elternprozess wird über die Beendigung seines Kindprozesses informiert. Auf diese Weise kann ein Prozess auf den Abschluss einer Aufgabe warten, die er an einen Kindprozess übertragen hat. Dieses Verhalten ist bei Kommandozeileninterpretern (auch als Shells bekannt) deutlich zu sehen. Wenn ein Befehl in eine Shell eingegeben wird, erscheint die Eingabeaufforderung erst dann wieder, wenn die Ausführung des Befehls beendet ist. Die meisten Shells ermöglichen eine Ausführung des Befehls im Hintergrund. Dazu wird einfach ein &
an das Ende des Befehls angehängt. Die Eingabeaufforderung wird dann sofort wieder angezeigt, was jedoch zu Problemen führen kann, wenn das abgesetzte Kommando seine eigenen Daten anzeigen muss.
B.5.2. Hintergrundprozesse (Dämonprozesse)
Ein „Daemon“ ist ein Prozess, der beim Hochfahren automatisch gestartet wird. Er läuft (im Hintergrund) weiter, um Verwaltungsaufgaben zu erledigen oder Dienste für andere Prozesse bereitzustellen. Diese „Hintergrundaufgabe“ ist genau genommen willkürlich und entspricht aus Sicht des Systems nichts Bestimmtem. Es sind, wie andere Prozesse auch, einfach Prozesse, die reihum laufen, wann immer ihr zugeteilter Zeitabschnitt kommt. Eine Unterscheidung gibt es nur in der menschlichen Sprache: ein Prozess, der ohne eine Interaktion mit einem Benutzer läuft (insbesondere ohne eine grafische Schnittstelle), wird als „im Hintergrund“ laufend oder als „Daemon“ bezeichnet.
B.5.3. Interprozesskommunikationen
Ein einzelner Prozess, ob ein Daemon oder eine interaktive Anwendung, ist selten für sich genommen nützlich. Daher gibt es verschiedene Methoden, um getrennten Prozessen die Kommunikation miteinander zu ermöglichen, entweder um Daten auszutauschen oder um sich gegenseitig zu steuern. Die allgemeine Bezeichnung hierfür lautet Interprozesskommunikation oder abgekürzt IPC.
Das einfachste IPC-System besteht darin, Dateien zu verwenden. Der Prozess, der Daten übersenden möchte, schreibt sie in eine Datei (mit einem zuvor bekannten Namen), während der Empfänger nur die Datei zu öffnen und den Inhalt zu lesen braucht.
In den Fällen, in denen man keine Daten auf einer Platte speichern möchte, kann man eine Pipe benutzen, die einfach ein Objekt mit zwei Enden ist; Bytes, die am einen Ende geschrieben werden, können am anderen gelesen werden. Wenn diese Enden von verschiedenen Prozessen kontrolliert werden, führt dies zu einem einfachen und praktischen Interprozesskommunikationskanal. Pipes können in zwei Arten unterschieden werden: benannte Pipes und anonyme Pipes. Eine benannte Pipe wird durch einen Eintrag im Dateisystem dargestellt (obwohl die übermittelten Daten dort nicht gespeichert sind), so dass beide Prozesse sie unabhängig voneinander öffnen können, falls der Ort der benannten Pipe vorab bekannt ist. In Fällen, in denen die Kommunikationsprozesse in Zusammenhang miteinander stehen (zum Beispiel ein Eltern- und sein Kindprozess), kann der Elternprozess auch eine anonyme Pipe erstellen, bevor er sich vervielfältigt, und der Kindprozess übernimmt sie dann. Beide Prozesse können sodann durch diese Pipe Daten miteinander austauschen, ohne das Dateisystem zu benötigen.
Jedoch werden nicht alle Interprozesskommunikationen zur Übermittlung von Daten benutzt. In vielen Situationen bestehen die einzigen Informationen, die übertragen werden müssen, aus Steuerungsmitteilungen wie „Ausführung anhalten“ oder „Ausführung fortsetzen“. Unix (und Linux) stellen einen Mechanismus bereit, der Signale genannt wird, durch den ein Prozess einfach ein Signal (aus einer festgelegten Liste mit Dutzenden vordefinierter Signale) an einen anderen Prozess senden kann. Die einzige Voraussetzung besteht hierbei darin, dass die PID des Zielprozesses bekannt ist.
Für komplexere Kommunikationen gibt es ebenfalls Mechanismen, die es einem Prozess ermöglichen, einem anderen Prozess Zugriff auf einen Teil des ihm zugeteilten Speicherplatzes zu gewähren oder ihn gemeinsam mit ihm zu benutzen. Der gemeinsam benutzte Speicherplatz ermöglicht es dann, Daten hin und her zu schieben.
Schließlich können auch Netzwerkverbindungen Prozessen helfen, miteinander zu kommunizieren; diese Prozesse können sogar auf verschiedenen Rechnern laufen, möglicherweise tausende von Kilometern voneinander entfernt.
Es ist für ein typisches Unix-artiges System recht normal, all diese Mechanismen in wechselndem Umfang zu verwenden.
Programmbibliotheken spielen in einem Unix-artigen Betriebssystem eine entscheidende Rolle. Sie sind nicht wirklich Programme, da sie für sich allein nicht ausgeführt werden können, sondern Ansammlungen von Code-Fragmenten, die von Standardprogrammen verwendet werden können. Unter den gängigen Bibliotheken sind vor allem folgende erwähnenswert:
die Standard-C-Bibliothek (glibc), die grundlegende Funktionen enthält wie das Öffnen von Dateien und von Netzwerkverbindungen und andere unterstützende Interaktionen mit dem Kernel;
grafische Werkzeugsätze, wie zum Beispiel Gtk+ und Qt, die es vielen Programmen ermöglichen, die grafischen Objekte, die sie bereitstellen, ihrerseits zu verwenden;
die libpng-Bibliothek, die das Laden, Interpretieren und Speichern von Bildern im PNG-Format ermöglicht.
Dank dieser Bibliotheken können Anwendungen bestehenden Code wiederverwenden. Ihre Entwicklung wird hierdurch entsprechend vereinfacht, insbesondere, wenn viele Anwendungen die gleichen Funktionen wiederverwenden. Da Bibliotheken häufig von verschiedenen Personen entwickelt werden, steht die allgemeine Entwicklung dieses Systems der historischen Philosophie von Unix sehr nahe.
Ferner werden diese Bibliotheken häufig als „gemeinsam benutzte Bibliotheken“ bezeichnet, da der Kernel sie nur einmal in den Speicher laden kann, selbst wenn gleichzeitig mehrere Prozesse dieselbe Bibliothek nutzen. Hierdurch kann im Vergleich zur entgegengesetzten (hypothetischen) Situation, bei der der Bibliothekscode so viele Male geladen würde, wie es Prozesse gibt, die ihn benutzen, Speicherplatz gespart werden.