# Multitasking

Der Begriff Multitasking [ˌmʌltiˈtɑːskɪŋ] (engl.) bzw. Mehrprozessbetrieb bezeichnet die Fähigkeit eines Betriebssystems, mehrere Aufgaben (Tasks) (quasi-)nebenläufig auszuführen. Im Allgemeinen bietet der Prozessor hierzu auch unterstützende Hardware-Strukturen. Die verschiedenen Prozesse werden in so kurzen Abständen immer abwechselnd aktiviert, dass der Eindruck der Gleichzeitigkeit entsteht. Multitasking ist somit eine Variante eines Zeit-Multiplexverfahrens. Besitzt ein Computer mehrere CPU-Kerne, so dass er mehrere Aufgaben echt-gleichzeitig ausführen kann, so spricht man von Multiprocessing. In modernen Computern werden beide Verfahren kombiniert eingesetzt.

## Zweck des Multitasking

Multitasking kann bei verschiedenen Anforderungen nützlich sein, insbesondere bei der Optimierung der Auslastung und für eine je nach Zielsetzung ausgeglichene oder prioritätsbasierte Ressourcenverteilung.
Der Grundgedanke hinter der „Optimierung der Auslastung“ ist der, dass in einem durchschnittlichen Rechner der überwiegende Teil der Rechenzeit nicht genutzt werden kann, weil häufig auf verhältnismäßig langsame, externe Ereignisse gewartet werden muss (beispielsweise auf den nächsten Tastendruck des Benutzers). Würde nur ein Prozess laufen (zum Beispiel die wartende Textverarbeitung), so ginge diese Wartezeit komplett ungenutzt verloren (siehe „aktives Warten“). Durch Multitasking kann jedoch die Wartezeit eines Prozesses von anderen Prozessen genutzt werden.
Ist ein Rechner bzw. seine Rechenzeit demgegenüber größtenteils ausgelastet, beispielsweise durch einzelne rechenintensive Prozesse, so können dennoch mehrere Benutzer oder Prozesse anteilige Rechenzeit erhalten, anstatt auf das Ende eines anderen Prozesses warten zu müssen. Dies kommt insbesondere auch der Interaktivität zugute.
Da das System zugleich für die verschiedenen Prozesse Prioritäten berücksichtigen kann, ist eine entsprechende Gewichtung möglich, je nach Zielsetzung. Ein Server kann zum Beispiel die Dienste bevorzugen, welche er anbieten soll, jedoch direkte Benutzer-Interaktionen niedrig priorisieren. Ein Desktop-PC wird umgekehrt vor allem die Ein- und Ausgaben von/an den Benutzer bevorzugen, und dafür Hintergrund-Prozesse etwas zurückstellen.

## Vorläufer und Entwicklung
### Multiprogrammierung und TSR-Programme

Vorläufer des Multitasking ist die Multiprogrammierung mit dem Ziel einer höheren CPU-Auslastung im Gegensatz zur sequenziellen Ausführung der Aufgaben bei Stapelverarbeitung. Bei der Multiprogrammierung findet der Kontextwechsel der Programme mit dem Zugriff auf periphere Geräte statt, da dabei zwangsläufig Wartezeit entsteht. Erste Ansätze basieren auf dem Konzept von Christopher Strachey aus dem Jahr 1959. Praktisch umsetzen ließen sich solche Konzepte aber erst mit leistungsfähiger Hardware, bei der mit der Interruptsteuerung die Entwicklung von TSR-Programmen möglich wurde.

### Allgemeiner Ablauf

Der technische Ablauf beim Multitasking ist im Prinzip immer gleich.
Als wichtige Grundvoraussetzung des Multitaskings gilt im Allgemeinen, dass ein Prozess, der zugunsten eines anderen unterbrochen wird, nichts über diesen anderen (oder ggf. auch mehrere andere) „wissen“ muss. Dies wird meist erreicht, indem jeder Prozess einen eigenen sogenannten Prozesskontext besitzt, der seinen Zustand beschreibt. Ein Prozess ändert immer nur seinen eigenen Prozesskontext, niemals den eines anderen Prozesses.
In der Regel wird der gesamte Prozesskontext (der Zustand des Prozesses) beim Unterbrechen gespeichert, z. B. auf dem Stapelspeicher (englisch Stack). Er bleibt so lange gespeichert, bis der betreffende Prozess wieder Rechenzeit erhalten soll. Unmittelbar bevor dieser Prozess wieder aktiv wird, wird der gespeicherte Zustand wieder geladen, sodass es für den Prozess so erscheint, als sei er überhaupt nicht unterbrochen worden; unabhängig davon, ob, wie viele und was für Prozesse in der Zwischenzeit ausgeführt worden sind. Dieses Umschalten zwischen einzelnen Prozessen wird als „Taskwechsel“ bezeichnet.
So kann ein Prozess bei der weiteren Ausführung nach der Unterbrechung wieder seine definierte Umgebung vorfinden, auch wenn zwischenzeitlich andere Prozesse ausgeführt wurden.
Beim kooperativen Multitasking ähnelt der Taskwechsel stark dem Aufruf von Prozeduren bzw. Funktionen in der prozeduralen Programmierung.

### Kooperatives Multitasking

Beim „kooperativen Multitasking“ wird das Multitasking durch eine zentrale Prozessverwaltung im Systemkernel realisiert: ein einfacher, sogenannter Scheduler. Der Scheduler sichert den Prozesskontext des gerade unterbrochenen Tasks, wählt den nächsten Prozess aus, der Rechenzeit erhalten soll, stellt dessen Prozesskontext her und gibt den Prozessor dann an diesen neuen Prozess ab. Der Scheduler kann Listen mit verschieden priorisierten Tasks führen, und niedrig priorisierte entsprechend selten aufrufen. Dabei kann auch die bereits verbrauchte Rechenzeit eines Tasks berücksichtigt werden. In der Regel werden Betriebssystem-interne Aufgaben zuerst erledigt, bevor ein neuer Task den Prozessor erhält. Es ist jedem Prozess selbst überlassen, wann er die Kontrolle an den Kern zurückgibt; in der Regel wird zumindest jede Dienst-Anforderung an das Betriebssystem mit einem Taskwechsel verbunden.
Vorteil dieser Methode ist, dass viele Systemfunktionen (z. B. die Ausgabe) nicht wiedereintrittsfähig sein müssen und daher nicht synchronisiert sein müssen, was eine erhebliche Vereinfachung für den Hersteller bedeutet. (Unterbrechungsroutinen müssen jedoch stets dieses Problem lösen.) Diese Form des Multitasking hat ebenso wie das TSR-Konzept den Nachteil, dass Programme, die nicht kooperieren, das restliche System zum Stillstand bringen. Gründe für solches Programmverhalten können sein:
* im Programm enthaltene Fehler;
* durch den Programmierer gewollte Fehlfunktion eines Systems;
* gewollte (vorteilhafte) „Alleinherrschaft“ des Programms, zum Beispiel für eine zeitkritische Anwendung wie ein Computerspiel.
Das Konzept wurde zum Beispiel eingesetzt
* beim Apollo Guidance Computer
* bei Windows 3.x: Unter diesem System wird Multitasking nur teilweise unterstützt, da nur die jeweiligen Speicherbereiche nebeneinander existieren und die Anwendungen im Hintergrund zugunsten des aktiven Programms einfach angehalten werden.
* bei vielen Heimcomputern wie zum Beispiel dem Atari ST.
* in grafischen Oberflächen für MS-DOS und dazu kompatibles DOS.
* System 5 – Mac OS 9
* (eingeschränkt) in erweiterten TSR-Programmen für PC-kompatibles DOS.
Diese Form des Multitasking ist prinzipiell schnell und ressourcenschonend sowie technisch verhältnismäßig einfach realisierbar. Für multiuserfähige Großrechner war es nie eine praktikable Alternative und wurde z. B. unter Unix nie eingesetzt, da ja ein Benutzer mittels unkooperativem Programm alle anderen blockieren könnte. Auch in den neueren Windows-Betriebssystemen der NT-Linie und in Mac OS X wird diese inzwischen als veraltet geltende Technik nicht eingesetzt. Teilweise unterstützen sie ähnliche Funktionalität begrenzt zum Beispiel als User Mode Threads, jedoch in jedem Fall nur eingebettet in präemptivem Multitasking.

### Präemptives Multitasking

Basis der heutzutage standardmäßig angewendeten Methode ist das präemptive Multitasking:
Der gerade laufende Prozess wird nach einer bestimmten Abarbeitungszeit (seinem „Zeitschlitz“, auch Zeitscheibe, engl. time slice) durch den Interrupt eines Hardware-Timers unterbrochen. Die Interrupt Service Routine (Teil des Betriebssystems) unterbricht den Prozess und sichert seinen Prozesskontext – der Prozess wird „schlafen gelegt“; dann übergibt sie an den Scheduler – das Betriebssystem hat (wieder) die Kontrolle erlangt. Sofern kein Betriebssystem-eigener Ablauf ansteht, wählt der Scheduler nun einen rechenbereiten Prozess aus (ggf. denselben, der gerade unterbrochen wurde), stellt dessen Prozesskontext wieder her, startet den Hardware-Timer und übergibt dann an den Prozess.
Meist wird jedem Prozess eine „absolute“ Zeitscheibe zugewiesen (alle Zeitscheiben haben die gleiche, feste Dauer; üblicherweise wenige Millisekunden); alternativ wird ihm pro definierter Zeiteinheit ein bestimmter Prozentteil dieser Zeiteinheit zugewiesen (z. B. abhängig von seiner Priorität), den er höchstens nutzen kann (die Länge der Zeitscheibe wird also jedes Mal neu bestimmt). Sollte er bereits vor Ablauf seiner Zeitscheibe eine Funktion des Betriebssystems benötigen, so wird er sogleich angehalten und als „nicht rechenbereit“ markiert, bis das Betriebssystem den gewünschten Dienst erbracht hat. Nur als „rechenbereit“ markierte Prozesse erhalten Prozessorzeit-Zuteilungen.

#### Auswahl des nächsten Prozesses

Eine beliebte Umsetzung des präemptiven Multitaskings ist die Verwendung einer Vorrangwarteschlange in Verbindung mit der Round-Robin-Scheduling-Strategie. Es gibt auch die Prozessorzuteilung abhängig von der Taskpriorität, vor allem bei Echtzeitsystemen z. B. MicroC/OS-II. Für das Multitasking spielt das nur eine untergeordnete Rolle, da präemptives Multitasking die Kernel- bzw. Prozessorkontrolle über die Prozesse beschreibt.

#### Notwendige Hardware-Unterstützung

Hardwareseitig benötigt präemptives Multitasking im Gegensatz zur kooperativen Variante (vergl. TSR-Programm als Vorläufer) zwingend einen Interrupterzeuger (meist ein Zeitgeber) im geeigneten Prozessor, da das System softwareseitig keine Möglichkeit hat, Prozessen die Kontrolle über den Prozessor zu entziehen. Der Zeitgeber sendet regelmäßig oder nach Ablauf einer eingestellten Zeit ein Signal (Interrupt) an die CPU, was sie zur Unterbrechung des aktuell laufenden Tasks und zur Ausführung der Betriebssystem-Interrupt-Service-Routine veranlasst.

#### Speicherschutz

Moderne Betriebssysteme arbeiten darüber hinaus mit einem Speicherschutz, der verhindert, dass verschiedene Prozesse sich im Speicher gegenseitig beeinflussen oder gar überschreiben. Diese Schutzfunktion übernimmt im PC die Memory Management Unit (MMU), welche die Virtualisierung des Hauptspeichers und verschiedene Berechtigungslevel (Ringe) oder auch Modi (Kernel-Mode versus User-Mode) ermöglicht und so dem Betriebssystem erlaubt, verschiedene parallele Prozesse innerhalb des Rechners voneinander strikt abzukapseln. Im PC kam die MMU erstmals in Rechnern mit i286-Prozessoren von Intel zum Einsatz. Diese Technik ist aber für Multitasking im engeren Sinne nicht zwingend notwendig.

#### Geschichte

Die ersten weit verbreiteten Computersysteme, die präemptives Multitasking beherrschten, waren der Sinclair QL (1984) und der Commodore Amiga (1985) im Heimbereich (beim Amiga ohne Speicherschutz/Privilegierung und somit „aushebelbar“) sowie zuvor die unter Unix betriebenen Großrechenanlagen. Windows beherrscht erstmals in den 3.x-Versionen teilweise präemptives Multitasking, dort allerdings nur für DOS-Programme und das auch nur dann, wenn sie auf einem System mit einem i386-kompatiblen Prozessor ausgeführt werden, da dieser in solchen Fällen hardwareseitige Virtualisierung ermöglicht. Moderne Betriebssysteme, die präemptives Multitasking vollständig unterstützen, sind Windows NT (und alle Nachfolger), QNX, BeOS und alle auf Unix basierenden Systeme wie Linux, HP-UX, Solaris, macOS u.v.m.

#### Abgrenzung zum Time-Sharing

Außerdem muss man zwischen Time slicing (Zeitscheiben-Verfahren) und Time-Sharing unterscheiden, letzteres gestattet mehreren Benutzern bzw. deren Prozessen (z. B. auf Datenbankservern oder Großrechnern mit Terminalzugriff) sich automatisch anteilig die verfügbare Rechenzeit zu teilen. Während sich also beim Multitasking mehrere Prozesse eines einzelnen Users die Rechenzeit teilen können, wird beim Time-Sharing die Zeit eines Prozesses auf mehrere Benutzer verteilt.

#### Präemptibles Multitasking

Eine Sonderform des präemptiven Multitasking ist das weniger bekannte Präemptible Multitasking (englische Schreibweise Preemptible Multitasking), das erstmals im Betriebssystem OS/2 implementiert wurde. Viele Betriebssystem-eigene Kernel-Routinen werden als Scheduler-Threads geführt; somit können Anwendungsprozesse auch Zeitschlitze erhalten, während eigentlich eine Betriebssystem-Aktion ausgeführt wird (mit Ausnahmen für atomare OS-Prozesse). Das Konzept ermöglicht schnellere Reaktionszeiten. Mit Version 2.6 hat es in den Linux-Kernel Eingang gefunden, wo zwischen präemptiblen und präemptiven Multitasking gewählt werden kann.