9 Multithreading und asynchrone Methodenaufrufe
9.1 Multithreading 

Stellen Sie sich eine beliebige Anwendung vor, die in der Lage ist, Mails zu versenden. Das Versenden kann, wenn die Mail mehrere größere Anhänge hat, durchaus einen längeren Zeitraum in Anspruch nehmen. Während des Versendens wird eine Sanduhr angezeigt, und der Anwender kann nicht mit der Applikation weiterarbeiten. Erstrebenswert ist es, dem Anwender eine Anwendung auszuliefern, die ohne eine Verzögerung auskommt. Dazu wäre nur eine Applikation in der Lage, die das Multithreading beherrscht. Mit einer solchen Anwendung könnte der Benutzer weiterarbeiten, während (scheinbar) gleichzeitig die Mail verschickt wird.
Die Entgegennahme der Benutzereingabe und das Versenden der Mail sind zwei Operationen, die in einer multithreading-fähigen Anwendung voneinander unabhängig sind und innerhalb eines einzigen Prozesses ablaufen. Beide Operationen können dabei dieselben Daten benutzen. Jeder Operation wird dazu ein eigener Thread zugeordnet. Ein Thread ist eine Ausführungseinheit und besteht aus einer kontinuierlichen Abfolge von Anweisungen. Sie werden weiter unten in den Beispielen noch sehen, wie das zu verstehen ist.
Jeder gestarteten Anwendung ist ein Prozess zugeordnet, in dem mindestens ein Thread existiert. Somit ist ein Thread die kleinste Ausführungseinheit und gehört im Umkehrschluss grundsätzlich immer zu einem Prozess. Wird der letzte Thread eines Prozesses zerstört, wird die Laufzeitumgebung der Anwendung beendet.
Wenn man eine Ein-Prozessor-Maschine voraussetzt, kann zu einem gegebenen Zeitpunkt nur ein Thread von der CPU bearbeitet werden. Stehen mehrere Threads derselben oder auch unterschiedlicher Anwendungen zur Ausführung in einer Warteschlange, erfolgt der Austausch der Threads in der CPU in sehr kleinen Zeitintervallen. Einem Anwender fällt das nicht auf – aus seiner Sicht erscheint es so, als würde die Ausführung gleichzeitig erfolgen.
Die gesamte Zeit, über die ein Mikroprozessor verfügt, veranschaulicht man sich häufig durch eine Kreisfläche, auch Zeitscheibe genannt. Die Zeitscheibe wird in eine bestimmte Anzahl von Kreisausschnitten aufgeteilt – diese entsprechen der Anzahl der aktiven Threads. Jeder Ausschnitt, der vom Betriebssystem und vom Prozessortyp abhängt, beschreibt eine gleich große Bogenlänge. Die Bogenlänge stellt die Prozessorzeit dar, die dem Thread zur Verfügung steht. Eine Komponente des Systems, der Scheduler, ist für die Zuteilung einer Zeitscheibeneinheit an einen wartenden Thread zuständig.
In Abbildung 9.1 stellt die CPU jedem Thread 20 Millisekunden zur Verfügung, gleichzeitig sind acht Threads gleichberechtigt aktiv. Der Prozess A ist daran mit vier Threads beteiligt, der Prozess B mit zwei und die Prozesse C und D mit je einem. Somit beschreibt die Zeitscheibe eine Gesamtzeit von 160 Millisekunden. Falls sich an der Bedingung nichts ändert, gelangt jeder Thread alle 0,16 Sekunden zur Ausführung, zu der ihm insgesamt 20 Millisekunden zur Verfügung stehen – einschließlich des Ladens der Daten aus dem Stack in die Register der CPU und des Entladens, wenn die Zeit für den Thread abgelaufen ist.
Abbildung 9.1 Die Zeitscheibe eines Mikroprozessors
Im Kontext jedes Threads sind alle Informationen enthalten, um die unterbrochene Ausführung zu einem späteren Zeitpunkt wieder problemlos aufnehmen zu können. Dazu gehören die Inhalte der CPU-Register zu dem Zeitpunkt, zu dem der Thread den Prozessor verlassen hat, sowie alle Informationen, die den Zustand des Threads beschreiben.





Jetzt bestellen





