Parallelität in Programmen

Parallelität (oder mindestens der Eindruck davon) wird immer auf dieselbe Art erreicht: mehrere Programme befinden sich gleichzeitig im (physikalischen) Hauptspeicher eines Computers. Wir gehen zunächst einmal davon aus, dass der Computer nur über einen Mikroprozessor verfügt. Dann kann nämlich nur ein Programm zu einem bestimmten Zeitpunkt aktiv sein (= die Kontrolle haben). Alle anderen Programme sind schlafen gelegt.

Wenn nun schnell genug zwischen den Programmen hin und her geschaltet wird, entsteht der Eindruck, als ob sie gleichzeitig ablaufen würden. Das Umschalten kann auf zwei Arten erreicht werden:

  1. kooperativ: Das Programm gibt freiwillig die Kontrolle ab, z.B. wenn es warten muss. Die Kontrolle wird dabei an das Betriebsystem zurückgegeben. Dieses entscheidet nun, ob es selbst Tätigkeiten zu verrichten hat (z.B. Daten von Eingabegeräten lesen), oder ob es die Kontrolle wieder an ein anderes Programm abgibt.
  2. preemptiv: Eine Systemuhr erzeugt nach einer bestimmten Zeit ein Signal, das aktive Programm wird unterbrochen und das Betriebssystem übernimmt die Kontrolle. Wie beim freiwilligen Umschalten, bestimmt auch hier das Betriebssystem was weiter passiert. Der Teil des Betriebssystems, der für das Umschalten zuständig ist nennt man Scheduler.

Das preemptive Verfahren garantiert ein faireres Umschalten zwischen den Programmen. Der Eindruck der Parallelität ist auch sanfter und ruckfreier. Natürlich ist es einem Programm auch hier nicht verboten die Kontrolle freiwillig abzugeben bevor es vom Scheduler unterbrochen wird. Prinzipiell sollte ein Programm nie warten, sondern immer die Kontrolle abgegeben. So wird nie ein Programm unnötig eine Warteschleife abarbeiten, während andere - die noch Arbeit hätten - schlafen.

Die Speicherverwaltung von parallel ablaufenden Programmen soll hier nicht unerwähnt bleiben. Wie der Speicher verwaltet wird, hat zwar nichts mit der Parallelität zu tun, jedoch mit Sicherheit. Wenn mehrere Programme gleichzeitig im Speicher sind, so kann es immer wieder vorkommen, dass absichtlich oder unabsichtlich die Programme sich gegenseitig den Speicher "kaputtschreiben". Zum Beispiel ist es möglich, dass ein Programm beginnt den Speicherbereich zu löschen, in dem ein anderes Programm steht. Um dies zu verhindern, wird bei manchen Betriebssystemen der physikalische Speicher in mehrere logische Speicher aufgeteilt. Jedes einzelne Programm erhält dadurch den Eindruck, ganz alleine über den gesamten Speicher zu bestimmen. Natürlich ist eine solche Speicherverwaltung aufwendig und bremst das Umschalten zwischen den Programmen stark.

Wie schon erwähnt, sind die Umschaltverfahren völlig unabhängig von der Speicherverwaltung Tabelle 1 gibt einen Überblick über die verschiedenen Kombinationsmöglichkeiten. Die hier aufgeführten Begriffe werden zum Teil auch synonym oder mit leicht anderer Bedeutung verwendet. In dieser Werkstatt jedoch halten wir uns an die unten gegebenen Bedeutungen.

Scheduling \ Speicher

gemeinsam

getrennt

kooperativ

Multitasking

 -

preemptiv

Multithreading

Multiprocessing

Tabelle 1: Parallelitätsarten

Multitasking:
Das hin und her schalten zwischen den Programmen wird vom Benutzer selbst gemacht, indem er z.B. in ein anderes Fenster klickt. Alle Programme teilen sich denselben Speicher, was das System sehr anfällig macht. Da jedes Programm vollen Zugriff auf den ganzen Computer hat, können z.B. Viren sehr einfach ein System befallen. Zudem ist es bei einem Programmabsturz meistens nötig den Computer neu zu starten, weil beim Absturz womöglich andere Programme "kaputtgeschrieben" wurden.
Beispiele für solche Systeme sind: DOS, Windows bis 3.11, MacOS
Multiprocessing:
Die komfortabelste Variante. Die Programmiererin muss sich weder um das Umschalten noch um die Integrität ihres Speichers sorgen machen. Allerdings wird eine gute Programmiererin auch hier daran denken die Kontrolle abzugeben, sobald ihr dies möglich ist. Der Sicherheitsvorteil wird durch eine erschwerte Kommunikation zwischen den Programmen erkauft. Zudem ist der Aufwand, der beim Umschalten zwischen mehreren Programmen nötig ist, gross. Multiprocessing bietet somit eine grobkörnige Parallelität.
Beispiele für Multiprocessing-Systeme: Windows NT, Unix-Systeme wie z.B. SunOS 4.1.3 oder Linux
Multithreading:
Wird meist auf Systemen mit Multiprocessing angeboten. Hierbei wird ein einzelnes Programm in mehrere Unterprogramme (= Threads) aufgeteilt, die sich gleichzeitig einen gemeinsamen Speicher teilen. Das Umschalten wird aber wie beim Multiprocessing automatisch gemacht. Multithreading bietet eine sehr feinkörnige Parallelität. Innerhalb eines Programmes sind die Interaktionen zwischen Threads auch sehr viel intensiver als zwischen zwei völlig verschiedenen Programmen. Da die Programmentwickler den Überblick über das gesamte Programm haben, sind sie auch verantwortlich dafür, dass sich zwei Threads nicht gegenseitig beeinträchtigen.
Beispiele für Systeme in denen Multithreading angeboten wird: Java, Windows 95 und NT oder Solaris (Unix)

Parallelität - Threads in Java - Tips und Hinweise - Lösungsmöglichkeit
OOP - Werkzeuge - Referenzen - Fäden - Synchronisation - Applets - Dokumentation
Werkstatt - Bibliographie