Next: Ein einfaches Beispiel mit
Up: Sprachmittel zur Synchronisierung
Previous: Bedingungen
Während für das Scheduling von Threads und Prozessen das
Betriebssystem zuständig ist, muß dies bei Koroutinen von
der Programmiersprache oder der Bibliothek gelöst werden.
In der Ulmer Oberon-Bibliothek ist die Schnittstelle hierfür
Tasks, wobei es möglich ist, selbst eigene Scheduler
zu definieren und sogar mehrere gleichzeitig zu verwenden in
Form einer hierarchischen Struktur.
Im Normalfall dürften allerdings die Voreinstellungen
reichen, die einen Scheduler auf Basis des Round-Robin-Schemas
vorsehen
Da Koroutinen nicht durch die Bibliothek verwaltet werden,
gibt es für den Scheduler handhabbare konkurrierende
Einheiten den Datentyp Tasks.Task. Normalerweise
ist eine Task direkt einer Koroutine zugeordnet - aber dies
muß nicht sein, da auch häufig Koroutinen kreiert werden,
die den Schedulern nicht direkt bekannt sind.
Wenn eine Koroutine mit Tasks.Create zur Task erhoben
und damit einem Scheduler bekannt gemacht wird, dann ist
es nicht mehr notwendig, sich um die Aktivierung dieser Koroutine
zu kümmern, da dies dann in der Verantwortung des Schedulers liegt.
Abbildung:
Zustandsübergänge für Tasks
|
Verbunden mit dem Leben einer Task sind folgende Grundoperationen,
die jeweils zu Zustandsübergängen führen, die in Abbildung
7.4 dargestellt sind:
- Tasks.Create
- kreiert eine Task, die zunächst mit
der gegebenen Koroutine assoziiert ist, deren Aktivierung
von nun an in der Verantwortung des Schedulers liegt.
Ihr Zustand ist zunächst ready, d.h. sie ist
rechenbereit, aber zur Zeit noch nicht aktiv.
- Tasks.Dispatch
- wird von dem Scheduler aufgerufen,
um eine Task zu aktivieren - sie ist anschließend im
Zustand running.
- Tasks.WaitFor
- erlaubt dann das Suspendieren
einer Task, bis eine Bedingung wahr wird. Alternativ
können auch Tasks.WaitForOneOf oder Tasks.Select
verwendet werden. Eine Task ist dann im Zustand waiting.
- Conditions.Test
- ist die wichtigste Operation
um später festzustellen, ob eine Task wieder aufgeweckt
werden kann, da ihre Wartebedingung erfüllt ist.
- Tasks.Suspend
- ermöglicht einen Zustandsübergang
von running zu ready. Dies wird nur in Fällen
rechenintensiver Tasks verwendet, um etwas Fairneß den
anderen Tasks gegenüber zu üben.
- Tasks.Terminate
- terminiert die aufrufende Task
und führt sie in den Zustand terminated. Wichtig ist
hier, daß eine Task nur sich selbst terminieren kann -
eine zu dem UNIX-Systemaufruf kill() vergleichbare
Operation ist nicht vorgesehen, da damit die Nachweisbarkeit
eines korrekten Programmablaufs unglaublich erschwert wird.
Next: Ein einfaches Beispiel mit
Up: Sprachmittel zur Synchronisierung
Previous: Bedingungen
Andreas Borchert
2/2/1998