So teile das Brot gerecht ...

Multitasking unter RISC OS


Eine überarbeitete Version der Artikels findet man unter http://www.arcsite.de/magazin/praxis/multitasking/



Das Betriebssystem des Archimedes bzw. Risc PC ist ein Multitaskingbetriebssystem. Multitasking bedeutet, daß der Computer in der Lage ist mehrere Programme quasi gleichzeitig abzuarbeiten. Der Benutzer kann z. B. einen Text schreiben, obwohl gleichzeitig eine Graphik gedruckt und eine Diskette formatiert wird. Im Idealfall merkt der Textschreiber nichts von den beiden andern Programmen bei seiner Texterstellung. Es gibt grundsätzlich zwei verschiedene Arten von Multitaskingbetriebssystemen.

Jedes Programm braucht die CPU um seine Aufgabe zu bewerkstelligen. Während ein Programm, auch Prozeß genannt, den Zentralprozessor beansprucht, schlafen die anderen Prozesse. Wenn ein Programm die CPU benutzt, muß es nach einer gewissen Zeit die CPU freigeben, damit die anderen Programme auch ihrer Aufgabe nachkommen können. Diese Art von Multitasking nennt man kooperatives Multitasking. Bei kooperativen Multitasking geben die Programme selbst immer wieder die CPU frei, damit andere Prozesse arbeiten können. Das Betriebssytem RISC OS des Archimedes bzw. Risc PC und auch Windows 3.x sind kooperativ.

Andere Betriebssyteme wie z. B. UNIX, OS/2, AmigaOS, Windos NT und mit Einschränkung Windows95 arbeiten mit einem preemptiven Multitasking. Dabei entscheiden nicht die Prozesse selbst wann die CPU freigegeben wird, sondern das Betriebssystem. Diese Entscheidung wann ein Programm den Zentralprozessor freigeben muß ist grundsätzlich zeitabhängig. Jedes Programm bekommt also nur eine bestimmte Zeit der CPU. So ist die Verteilung der Prozesse auf die CPU fest geregelt. Da das Betriebssystem die Verteilung der CPU-Zeit koordiniert, braucht sich der Programmierer nicht mit einer Multitasking-Programmierung zu kümmern (sofern jeder Prozeß unabhängig von anderen Prozessen läuft).

Bei beiden Betriebssystemsarten wird bei Zugriffen auf Geräte, also z. B. die Festplatte, die CPU an einen anderen Prozeß weitergegeben. Da der Zugriff auf die Festplatte für die CPU sehr lange dauert, ist es auch sinnvoll die Wartezeit mit einen anderen Aufgabe auszufüllen. Der Programmierer braucht sich also in so einen Fall nicht um eine Multitasking-Programmierung zu kümmern. Windows 3.x, DOS sei dank, macht da eine Ausnahme und blockiert den Rechner bei Plattenzugriffen mit Nichtstun.

Wie schon beschrieben muß jedes Programm beim kooperativen Multitasking selbst die CPU freigeben, damit die anderen Prozesse auch zum Zuge kommen. Doch leider erlebt man unter RISC OS immer wieder Programme die den Rechner blockieren. Diese Programme sind nicht kooperativ. Dieser Artikel will zeigen, wie man kooperative Programme schreibt.

Das folgende BASIC-Fragment zeigt wie das Programm per Wimp_Poll die CPU freigibt und erst bei einem Ereignis, z. B. einen Mausklick, wieder den Zentralprozessor bekommt. Ich möchte hier nicht auf diese Konstruktion eingehen, weil diese elementare Wimp-Programmierung ist. Ich setze aber voraus, daß man grundsätzlichen Techniken der WIMP-Programmierung beherrscht

...
SYS "Wimp_Initialise", ...
...
REPEAT
  SYS "Wimp_Poll", ...
  Behandle Ereignis
UNTIL ewig

Wenn die eigentliche Arbeit des Programmes sehr schnell abgearbeitet ist reicht die obige Konstruktion aus, denn die anderen Prozesse werden ja nicht in ihren Arbeit ernsthaft gestört. Braucht das Programm viel Rechenzeit, also ab mehreren Sekunden, dann blockiert dieses Programm merklich die anderen Programme. Nun sollte, nein muß, man das Programm kooperativ schreiben.


Das Grundgerüst für alle Beispielprogramme

DIM blk% 256
REM Beim StrongARM rounds% und work% erhoehen!
rounds% = 200
work% = 300
event% = 0
freq% = 10
SYS "Wimp_Initialise", 200, &4b534154, "Multitask" TO , task%
start% = TIME
diff% = start%
FOR i% = 1 TO rounds%

  REM hier bitte Zeilen einfügen

NEXT i%
blk%!0 = 999
$(blk% + 4) = STR$((TIME - start%) / 100) + " Sekunden" + CHR$(0)
SYS "Wimp_ReportError", blk%, 17, "Multitask"
SYS "Wimp_CloseDown", task%
END
DEF PROCcalc(x)
  y = 9.9
  FOR j% = 1 TO work%
    x = x + SIN(ATN(COS(LOG(y))))
  NEXT j%
ENDPROC


Wenn man folgende Zeilen in die FOR-Schleife des Listings einfügt, erhält man ein kooperatives Programm:

SYS "Wimp_Poll", &1ce3972, blk% TO event%
CASE event% OF
  WHEN 0: PROCcalc(i%)
ENDCASE

Wie funktioniert das Programm, daß man wie die folgenden auch laden kann? Zuerst wird das Programm zu einer Task bzw. Aufgabe gemacht (Wimp_Initialise). Dann wird mit der Funktion TIME die aktuelle Zeit gesichert. In der folgenden FOR-Schleife wird mit Wimp_Poll die CPU freigegeben, also können nun andere Programme ihr Werk verrichten. Tritt ein Ereignis für das Programm auf, wird mit der CASE-Anweisung das Ereignis ausgewertet. Im Beispielprogramm wird nur das Ereignis Null_Reason_Code ausgewertet. Dieses Ereignis tritt auf, wenn die CPU gerade kein anderes Programm bedienen muß. Nun wird in der Prozedur calc die etwas sinnlose Berechnung abgearbeitet. Dank der FOR-Schleife gibt das Programm den Prozessor wieder frei, bis zum nächsten "Hab-nichts-zu-tun". Dies wiederholt sich, bis die FOR-Schleife alle Durchläufe hinter sich hat. Am Schluß wird die Laufzeit des Programmes ausgegeben. Um zu sehen, ob überhaupt das Programm läuft, muß man mit einem Blick auf den Aufgabenmanager (ein Klick auf die Eichel) werfen.

Bei diesem Programm wird recht oft die CPU anderen Prozessen überlassen. Wenn das Unterprogramm calc schnell abgearbeitet ist, kann man, bevor das Programm schlafen geht, calc auch mehrere Male hintereinander aufrufen. In dem nächsten Beispielprogramm wird in die FOR-Schleife folgende Zeilen eingesetzten:

IF i% MOD freq% = 0 THEN
  SYS "Wimp_Poll", &1ce3972, blk% TO event%
ENDIF
CASE event% OF
  WHEN 0: PROCcalc(i%)
ENDCASE

Mit der IF-Abfrage wird erst bei jeden zehnten (siehe Variable freq%) Durchgang der FOR-Schleife das Programm schlafen gelegt. Durch diese Maßnahme wird das Programm schneller abgearbeitet. Doch leider laufen die anderen Aufgaben der CPU, z. B. Fenster verschieben, (mit einem ARM 3) nicht mehr so flüssig wie mit dem ersten Programm. Man kann aber mit der Variablen freq% die Häufigkeit des Schlafengehens verändern. So kann man die Laufzeit des Programmes beschleunigen oder verlangsamen und damit den andern Prozessen weniger bzw. mehr CPU-Zeit geben.

IF TIME > diff% + freq% THEN
  SYS "Wimp_Poll", &1ce3972, blk% TO event%
  diff% = TIME
ENDIF
CASE event% OF
  WHEN 0: PROCcalc(i%)
ENDCASE

In der dritten Programmvariante wird anhand der Laufzeit entschieden, wann die anderen Programme arbeiten dürfen. In der IF-Abfrage wird geprüft ob eine bestimmte Zeit (im Beispiel 1/10 Sekunde) vergangen ist. Wenn die Zeit noch nicht erreicht worden ist wird das Unterprogramm calc abgearbeitet. Ist die Zeit verstrichen, wird mit Wimp_Poll die CPU freigegeben. Dieses Programm behindert die anderen Programme weniger als das vorherige, aber dafür läuft es etwas länger. Diese Konstruktion ist recht günstig, da dieses Programm unabhängig von der Prozessorgeschwindigkeit in mehr oder weniger regelmäßigen Abständen (maximal freq% plus Dauer von calc) zu Bett geht.

Auch Acorn hat sich gedacht, daß eine zeitliche Variante die beste ist und hat deshalb den Befehl Wimp_PollIdle ins RISC OS gebracht. Dieser Befehl regelt, wann frühestens das Programm wieder die CPU bekommt. Der Aufruf von Wimp_PollIdle entspricht fast dem von Wimp_Poll:

R0: Poll-Maske
R1: 256 Bytes Ereignis-Puffer
R2: Zeit nachdem ein Null_Reason_Code frühestens in das Programm zurückkehren darf
R3: Zeiger auf das Poll-Wort (ab RISC OS 3)

Mit dem Register 2, daß in Wimp_Poll unbenutzt ist, stellt man also die Dauer, die das Programm mindestens schläft, ein und gibt solange den anderen Prozessen die Möglichkeit sich zu entfalten. Die Funktionsweise von Wimp_PollIdle kann man mit folgenden Zeilen, eingefügt in das Listing, ergründen.

SYS "Wimp_PollIdle", &1ce3972, blk%, freq% TO event%
CASE event% OF
  WHEN 0: PROCcalc(i%)
ENDCASE

Wie im ersten Programm ist die Konstruktion sehr einfach. Mit der Variablen freq% wird die minimale Schlafdauer eingestellt. Ist die Schlafenszeit beendet und es tritt das Ereignis Null_Reason_Code auf wird das Unterprogramm calc abgearbeitet. Diese Programm blockiert die anderen Aufgaben der CPU nicht, läuft aber am längsten von allen Programmen. Wie im drittem Programm ist das Multitasking mit Wimp_PollIdle unabhängig von der CPU-Geschwindigkeit und eignet sich für unterschiedliche CPU's, da das Programm mindestens eine definierte Zeit schläft.

Die beiden letzten Programme sind besser als die ersten beiden, weil sie nach einer bestimmten Zeit die CPU freigeben bzw. wieder erhalten. Sie sind also nicht so sehr abhängig von der CPU-Geschwindigkeit. Die Entscheidung welche der beiden Verfahren das richtige ist, hängt von den Programmgegebenheit ab. Eine langwierige Berechnung wird man wohl in bestimmten Zeitabschnitten unterbrechen (Programm 3). Muß ein Programm in bestimmten Zeitintervallen die CPU haben (z. B. eine Uhr), wird man nicht um den SWI Wimp_PollIdle (Programm 4) kommen. Zusätzlich kann man natürlich beide Programme kombinieren.

Den Ruf nach einem preemptiven RISC OS nachzukommen wird sich Acorn, wenn überhaupt, sehr schwer tun. Aber wie man sieht ist die Programmierung von Multitasking-Programmen gar nicht so schwer und ich hoffe, daß immer mehr Programmierer sich an diese Programmierung heranwagen. Leider brauchen alle Multitasking-Programme länger für die Berechnung als ein Singletask-Programm, aber dafür kann man während eine langwierige Berechnung immer noch andere Aufgaben mit dem Rechner bearbeiten. Die Programmierer können natürlich eine Einstellung in ihren Programmen einbauen, um das Programm zu beschleunigen; also ins Singeltask schalten. So kann der Benutzer selbst entscheiden ob das Programm im Multitasking oder schnell arbeiten soll.

Am Schluß noch ein Tip: Man kann ein Singletask-Programm mit dem *TaskWindow Kommando oder mit einer TaskObey-Datei zu einem Multitasking-Programm zwingen. Doch leider funktioniert dies nur bei einfachen Programmen, die keine Task (siehe SWI Wimp_Initialise) sind. Auch diese beiden Möglichkeiten sind in den Beispielen. Ansonsten kann man ja den Programmautor dazu auffordern sein Programm umzuschreiben.

Carlos Michael Santillán

Beispiele laden (Zip, 3,6 kByte)