Der Begriff Interprozesskommunikation (, kurz IPC) bezeichnet in der Informatik verschiedene Verfahren des Informationsaustausches zwischen den Prozessen eines Systems. Mithilfe eines Shared Memory erfolgt die Kommunikation dadurch, dass mehrere Prozesse auf einen gemeinsamen Datenspeicher zugreifen können, beispielsweise gemeinsame Bereiche des Arbeitsspeichers. Bei einer Message Queue dagegen werden Nachrichten von einem Prozess an eine Nachrichtenschlange geschickt, von wo diese von einem anderen Prozess abgeholt werden können.
Die Kommunikation zwischen den Prozessen sollte in einer gut strukturierten Weise erfolgen. Um Race Conditions zu vermeiden, sollten die kritischen Abschnitte, in denen auf gemeinsam genutzten Speicher zugegriffen wird, vor einem (quasi-)gleichzeitigen Zugriff geschützt werden. Dies kann durch verschiedene Mechanismen wie Semaphore oder Monitore realisiert werden. Wenn jedoch jeder Prozess aus einer Menge von Prozessen auf ein Ereignis wartet, das nur ein anderer Prozess aus der Menge auslösen kann, entsteht eine Deadlock-Situation.
Klassische Problemstellungen der Interprozesskommunikation sind das Erzeuger-Verbraucher-Problem, das Philosophenproblem und das Leser-Schreiber-Problem.
Grundlagen
Ein Programm ist eine den Regeln einer bestimmten Programmiersprache genügende Folge von Anweisungen (bestehend aus Deklarationen und Instruktionen), um bestimmte Funktionen bzw. Aufgaben oder Probleme mithilfe eines Computers zu bearbeiten oder zu lösen.ISO/IEC 2382-1:1993 definiert „computer program“: „A syntactic unit that conforms to the rules of a particular programming language and that is composed of declarations and statements or instructions needed to solve a certain function, task, or problem.“ Bis 2001 definierte die DIN 44300 „Informationsverarbeitung Begriffe“ identisch. Jedes Programm wird normalerweise in einem (Betriebssystem-)Prozess ausgeführt, der zum Ablauf einem Prozessor zugeordnet werden muss. Ein Prozess stellt auf einem Rechnersystem die Ablaufumgebung für ein Programm zur Verfügung und ist eine dynamische Folge von Aktionen mit entsprechenden Zustandsänderungen, oder anders gesagt, die Instanzierung eines Programms. Als Prozess bezeichnet man auch die gesamte Zustandsinformation eines laufenden Programms.Mandl: Grundkurs Betriebssysteme. 4. Aufl., 2014, S. 78. Werden verschiedene Prozesse in kurzen Abständen immer abwechselnd aktiviert, entsteht der Eindruck von Gleichzeitigkeit, auch wenn zu jedem Zeitpunkt unter Umständen immer nur ein Prozess verarbeitet wird (oder zumindest die Anzahl der Prozesse wesentlich höher ist als die Anzahl der vorhandenen CPUs).Tanenbaum: Moderne Betriebssysteme. 3. Aufl., 2009, S. 124–125.
In Multitasking-Systemen laufen die meisten Prozesse nebenläufig und wissen kaum etwas voneinander. Ein Speicherschutz schützt das Betriebssystem davor, dass ein Prozess auf die Speichersegmente eines anderen Prozesses zugreifen kann (und so die Stabilität des Systems beeinträchtigen würde). Voraussetzung dafür ist eine Memory Management Unit (Speicherverwaltungseinheit, kurz MMU). Dennoch gibt es Anwendungsfälle, bei denen Prozesse mit anderen Prozessen kommunizieren müssen. Einige davon sind: Mehrere Prozesse müssen spezielle Daten gemeinsam verwenden. Die Prozesse sind untereinander abhängig und müssen aufeinander warten. Daten müssen von einem Prozess an einen anderen weitergereicht werden. Die Verwendung von Systemressourcen muss koordiniert werden.Jürgen Wolf: Linux-UNIX-Programmierung. Das umfassende Handbuch. 3., aktualisierte und erweiterte Auflage, Galileo Computing: Bonn, 2009, S. 275.
mini|Drei Prozesse greifen gleichzeitig auf eine geteilte Ressource zu.
Kommunikation meint in diesem Zusammenhang grundsätzlich den Austausch von Informationen nach bestimmten Regeln. Sie sollte also in einer gut strukturierten Weise erfolgen. Das Regelwerk fasst man in der Datenkommunikation bzw. bei Rechennetzwerken unter dem Begriff Protokoll zusammen.Mandl: Grundkurs Betriebssysteme. 4. Aufl., 2014, S. 196.
Beispiele:
Drucker-Spooler: Wenn ein Prozess eine Datei drucken möchte, trägt er den Dateinamen in einen speziellen Spoolerordner (spooler directory) ein. Ein anderer Prozess, der Drucker-Daemon (printer daemon), überprüft zyklisch, ob es irgendwelche Dateien zu drucken gibt. Wenn es welche gibt, druckt er diese aus und entfernt danach ihren Namen wieder aus dem Ordner.Tanenbaum: Moderne Betriebssysteme. 3. Aufl. 2009, S. 162. Pipe: Durch die Eingabe eines „|“-Zeichens in der Unix-Shell wird die Ausgabe eines ersten Prozesses an einen zweiten Prozess weitergereicht.
Man nennt zwei Prozesse konkurrent, wenn es mindestens ein Zeitintervall gibt, in dem sie beide begonnen, aber nicht abgeschlossen sind. Im Einprozessorsystem können konkurrente Prozesse nur abschnittweise sequentiell bearbeitet werden, während im Mehrprozessorsystem datenunabhängige Abschnitte gleichzeitig ausgeführt werden können.Wolfgang K. Giloi: Rechnerarchitektur. 2. Auflage, Springer-Verlag: Berlin, Heidelberg, 1993, S. 48.
Ein Betriebsmittel muss in dem Sinne determiniert sein, dass unter der Kontrolle des Betriebssystems ablaufende Programme jeweils identische Resultate liefern, unabhängig davon, in welcher Umgebung sie ablaufen, d. h. unabhängig mit welchen anderen Programmen zusammen. Andererseits sind die tatsächlichen Vorgänge nicht-determiniert, da es möglich sein muss, auf Ereignisse unabhängig von der Reihenfolge ihres Auftretens zu reagieren. Solche Ereignisse sind beispielsweise Betriebsmittelanforderungen, Laufzeitfehler und asynchrone Unterbrechungen, die von Ein- und Ausgabegeräten erzeugt werden.Lutz Richter: Betriebssysteme. 2. Auflage, B. G. Teubner: Stuttgart, 1985, S. 41.
Techniken
Speicherbasierte Kommunikation
Shared Memory
Mit der Shared Memory stellt das Betriebssystem einen Mechanismus bereit, durch den mehrere Prozesse auf einen gemeinsamen Datenspeicher zugreifen können. Um dies zu ermöglichen, muss ein Prozess als Erstes einen gemeinsamen Datenspeicher anlegen. Danach müssen alle Prozesse, die ebenfalls darauf zugreifen sollen, mit diesem Datenspeicher bekannt gemacht werden: Dies geschieht, indem der Speicherbereich im Adressraum der entsprechenden Prozesse eingefügt wird (siehe auch Speicherverwaltung). Ebenfalls muss hierbei den Prozessen mitgeteilt werden, wie diese auf den Speicherbereich zugreifen können (lesend / schreibend). Wurde all dies erledigt, kann der Datenspeicher wie ein gewöhnlicher Speicherbereich verwendet werden.
Shared Memory ist die schnellste Form der Interprozesskommunikation, da von zwei oder mehreren Prozessen ein bestimmter Speicherbereich gemeinsam benutzt wird, und somit das Kopieren zwischen Server und Clients nicht notwendig ist. Für eine ordnungsgemäße Kommunikation muss jedoch darauf geachtet werden, dass die einzelnen Prozesse untereinander synchronisiert werden. Als Mechanismus für die Prozesssynchronisation werden häufig Monitore oder Semaphore verwendet.Jürgen Wolf, Klaus-Jürgen Wolf: Linux-Unix-Programmierung. Das umfassende Handbuch. 4. Aufl., Rheinwerk Verlag: Bonn, 2016, S. 354, 424-427; ferner Mandl: Grundkurs Betriebssysteme. 2014, S. 198.
Bei der Speicherverwaltung mittels Paging kann Shared Memory durch die Verwendung von gemeinsamen Seiten umgesetzt werden. Es verweisen dabei mehrere Seitentabelleneinträge verschiedener Prozesse auf gemeinsam genutzte Speicherbereiche (Seitenrahmen) im physischen Arbeitsspeicher.Mandl: Grundkurs Betriebssysteme. 2014, S. 344.
Kommunikation über Dateien
Eine einfache Form der Kommunikation ist der Austausch von Dateien: Ein Prozess kann Daten in Dateien schreiben, die ein anderer Prozess ebenfalls lesen (oder beschreiben) kann. Diese Variante erfordert ebenfalls eine Synchronisation. Häufig bietet das Betriebssystem einen Lock-Mechanismus an, der ganze Dateien sperrt. Es sind aber auch klassische Mechanismen wie Semaphore möglich.Mandl: Grundkurs Betriebssysteme. 2014, S. 199.
Nachrichtenbasierte Kommunikation
Message Queue (Nachrichtenschlange)
mini|hochkant=1.5|Kommunikation über eine Nachrichtenschlange: Mit enter wird ein neuer Wert (3) der Schlange hinzugefügt, und mit leave das am längsten gespeicherte Element (37) herausgenommen (FIFO-Prinzip). Bei diesem Mechanismus werden Nachrichten von einem Prozess an eine Message Queue (dt. Nachrichtenschlange) geschickt, die in Form einer verketteten Liste verwaltet wird. Dort kann die Nachricht von einem anderen Prozess abgeholt werden. Jede Message Queue hat eine eindeutige Kennung, wodurch sie auch von einem anderen Prozess identifiziert werden kann. Normalerweise wird nach dem First-In-First-Out-Prinzip (FIFO) gearbeitet. Die Nachrichten können aber auch mit einer Priorität versehen werden. Wenn ein Prozess eine Nachricht mit einer Priorität N abholt, holt er sich in der Schlange (Queue) die erste Nachricht mit der Priorität N, auch wenn diese beispielsweise als letzte eingefügt wurde.Jürgen Wolf, Klaus-Jürgen Wolf: Linux-Unix-Programmierung. Das umfassende Handbuch. 4. Aufl., Rheinwerk Verlag: Bonn, 2016, S. 354, 411.
Warteschlangen werden beispielsweise häufig zur Datenübergabe zwischen asynchronen Prozessen in verteilten Systemen verwendet, wenn also Daten vor ihrer Weiterverarbeitung gepuffert werden müssen. Der Zugriff erfolgt dabei durch im Betriebssystem verankerte APIs. Die Größe der Warteschlange wird durch das Betriebssystem limitiert.
(Namenlose) Pipes
mini|Kommunikation zweier Prozesse über eine Pipe Die Pipe (oder Pipeline, von engl. Rohrleitung) ist eine der wichtigsten Anwendungen für Warteschlangen. Es handelt sich um einen Datenstrom zwischen zwei Prozessen durch einen Puffer nach dem FIFO-Prinzip. Das bedeutet vereinfacht, dass ein Ergebnis eines Computerprogramms als Eingabe eines weiteren Programms verwendet wird. Es handelt sich um die älteste und erste Technik der Interprozesskommunikation. Sie wurde 1973 von Douglas McIlroy für das Betriebssystem Unix erfunden.
Eine Pipe besitzt immer die folgenden zwei grundlegenden Eigenschaften: Bei einer Pipe können Daten immer nur in eine Richtung fließen. Ein Prozess kann praktisch immer nur in eine Pipe schreiben oder aus einer Pipe lesen. Will man anstatt der Halbduplex-Verbindung eine Vollduplex-Verbindung erstellen, benötigt man dazu zwei Pipes zwischen den Prozessen. Pipes können nur von Prozessen eingerichtet werden, die gemeinsame Vorfahren besitzen. Gewöhnlich wird eine Pipe eingerichtet, indem ein Elternprozess eine Pipe erzeugt und einen Kindprozess mittels fork() kreiert, der dabei diese Pipe erbt. Anschließend steht einer guten Kommunikation zwischen dem Elternprozess und dem Kindprozess nichts mehr im Wege.Jürgen Wolf, Klaus-Jürgen Wolf: Linux-Unix-Programmierung. Das umfassende Handbuch. 4. Aufl., Rheinwerk Verlag: Bonn, 2016, S. 359.
In unixoiden Betriebssystemen werden die Programme über das Pipe-Symbol „|“ verbunden. Beispielsweise sendet
who | sort
die Standardausgabe des Befehls who in die Standardeingabe des sort-Befehls, wodurch eine alphabetisch geordnete Liste der angemeldeten Benutzer ausgegeben wird.Daniel J. Barrett: Linux. kurz & gut. 2. Aufl., O’Reilly: Beijing, u. a., 2012 (Deutsche Übersetzung von Kathrin Lichtenberg). Der gemeinsame Vorfahr beider Prozesse ist dabei die Shell, in der die Befehlsverkettung angewiesen wurde.
Benannte Pipes (FIFO-Pipes)