News   Magazin   Börse   Links   ArcArchie   Homepages
 Magazin  RISC OS & C-Programmierung 5: Multitasking und Pollschleife Home 
Hardware   Software   Praxis   Sonstiges  
RISC OS & C-Programmierung: Multitasking und Pollschleife  Alexander Ausserstorfer und Carlos Michael Santillán 14. 4. 2015

Unter Multitasking versteht man die quasi gleichzeitige Ausführung von Programmen. RISC OS verfügt über kooperatives Multitasking. Als solches wechselt die Kontrolle ständig zwischen dem Betriebssystem sowie den Programmen hin und her. Allerdings betrifft das nur den grafischen Teil von RISC OS, also den Desktop. Sobald man vom Desktop aus die Taste F12 drückt, hat man dieses System verlassen. Öffnet man ein Taskwindow (Strg/Ctrl F12) hat man aber auch in der Kommandozeile Multitasking. Dies ist aber ein anderes Thema.

Kooperatives Multitasking heißt, das Betriebssystem übergibt einem Programm die Rechenzeit und das Programm arbeite dann eine Zeitlang. Dann gibt das Programm von sich aus die Rechenzeit wieder an das Betriebssystem zurück. Das wählt dann das nächste Programm aus. Auch das gibt nach einiger Zeit die Rechenzeit wieder ab, damit das nächste Programm arbeiten kann. Das geht dann so weiter, damit jedes laufende Programm seine Arbeit nach und nach erledigen und der Benutzer vor dem Bildschirm am Computer arbeiten kann. Dabei steuern die Programme selber, wann sie ihre Rechenzeit abgeben. Im Idealfall geben die Programme recht schnell ihre Rechenzeit wieder ab und der Benutzer vor dem Bildschirm erhält ein flüssiges System. Aber bei kooperativen Multitasking können Programme die Rechenzeit behalten, bis deren Arbeit abgeschlossen ist. Solche Programme blockieren damit den Rechner, so das die Arbeit vor dem Bildschirm recht zäh wird oder sogar für Minuten unmöglich ist. Damit bei RISC OS Multitasking funktioniert, müssen die Programme so geschrieben werden, dass sie auch kooperativ sind.

Aber man darf nicht vergessen, dass viele Programm die man tagtäglich benutzt, nicht ständig viel Rechenzeit brauchen. Oft wird die Aufgabe, die der Benutzer zum Beispiel per Mausklick angestoßen hat, innerhalb einer Sekunde abgearbeitet. Dann braucht man das oben beschriebene Multitasking überhaupt nicht. Dann braucht man ein Multitasking, das auf Benutzereingaben, wie den Klick auf OK, wartet um aktiv zu werden.

Zuständig für das Multitasking ist ein Betriebssystemmodul mit dem Namen WindowManager. Dieses verwaltet das Multitasking der grafischen Oberfläche von RISC OS, dem Desktop (englisch für Schreibtisch) oder der WIMP (Windows, Icons, Menus, Pointer, also Fenster, Symbole, Menüs und Zeiger). Ein Programm, das im Multitasking laufen soll, muss extra dafür geschrieben worden sein. Dafür stellt RISC OS viele Betriebssystemroutinen beziehungsweise Funktionen bereit.

In C kann man diese Betriebssystemroutinen mit Hilfe der Library OSLib anspringen.

   #include "oslib/wimp.h"

   int main() {
     wimp_version_no version_out;
     wimp_t task_handle;

     task_handle = wimp_initialise(310, "OSLib_Example 1", NULL, &version_out);
     wimp_close_down(task_handle);

     return 0;
   }
							

Die Bedeutung der einzelnen Parameter der SWIs sind grundsätzlich in den PRMs nachzulesen. Hier aber die wichtigsten Parameter der benutzen Funktionen. Mit dem ersten Parameter der Funktion wimp_initialise() (PRM 3-85) wird angegeben welche die kleinste RISC OS Version ist mit dem das Programm läuft. Hier ist mit 310 RISC OS 3.10 gemeint. Für RISC OS 2 gelten bei der Programmierung zum Teil andere Regeln, auf die hier nicht eingegangen wird. Nutzt man SWIs, die zum Beispiel nur ab RISC OS 4.0 funktioniert, muss man 400 angeben. Mit dem zweiten Parameter gibt man dem Betriebssystem den Namen des Programms bekannt. Den Programmnamen kann man dann im Taskmanager sehen. Den Taskmanager kann man mit einem Klick auf den Switcher, das Raspberry Pi Symbol rechts unten, öffnen. Unter Application tasks findet man dann die Anwendungen. Damit hat man eine Task (englisch für Aufgabe) bei RISC OS angemeldet. Mit der Funktion wimp_close_down() (PRM 3-175) meldet man diese Task wieder ab. Das Programm oben ist nicht nur sehr kurz, sondern auch ohne Nutzen. Es meldet das Programm OSLib_Example 1 beim Betriebssystem an um es sofort wieder abzumelden und dann das Programm zu beenden. Zwischen wimp_initialise() und wimp_close_down() muss jetzt etwas Sinnvolles eingefügt werden. Bevor man das Programm abtippt, sollte man vielleicht dieses und die folgenden Programme im Quellkode herunterladen.

Bei RISC OS wird die Rechenzeit des Programms über den SWI Wimp_Poll (PRM 3-115) an RISC OS abgegeben. Bei OSLib heißt die Funktion wimp_poll()). Ein erstes Multitaskingprogramm würde damit wie folgt aussehen.

   #include "oslib/wimp.h"

   int main() {
     wimp_version_no version_out;
     wimp_t task_handle;
     wimp_event_no event;
     wimp_poll_flags mask = 1;
     wimp_block block;

     task_handle = wimp_initialise(310, "OSLib_Example 2", NULL, &version_out);
     event = wimp_poll(mask, &block, NULL);
     wimp_close_down(task_handle);

     return 0;
   }
							

Programm beenden Das Programm erstellt die Task OSLib_Example 2 und übergibt dann die Rechenzeit an das Betriebssystem und man kann im Desktop mit den anderen Programmen arbeiten. Schaut man nun in den Taskmanager, findet man OSLib_Example 2. Das Programm läuft also und wartet, dass es die Rechenzeit übergeben bekommt. Auch sehr Geduldige werden sehr lange warten müssen. Dem Programm fehlt noch etwas. Aber wenigstens blockiert das Programm nicht den Desktop. Wenn man nun im Taskmanager die Menütaste, also die mittlere Maustaste, über OSLib_Example 2 klickt, kann man über das Submenü von Task 'OSLib_Example 2' mit einem Klick auf Quit das Programm beenden.

Wenn RISC OS sich an Multitaskingprogramme wendet, so geschieht das über Ereignisse die von wimp_poll() empfangen werden. Es gibt eine Reihe von Ereignissen. Zum Beispiel entsteht ein Ereignisse wenn man im Bereich des Programms mit der Maus klickt, auf der Tastatur tippt und so weiter. Jedes der Ereignisse hat einen eigenen Code, also eine Nummer. Diesen Code kann dann das Programm auswerten und dann zum Beispiel das Programmfenster schließen. Der Funktionsaufruf von wimp_poll() liefert hier die vorliegende Ereignisnummer in der Variablen event zurück. Jedes Ereignis schreibt dabei zusätzliche Informationen in den Datenblock, der hier block heißt. Das Programm muss auf entsprechende Ereignisse reagieren und dabei den Datenblock geeignet auswerten. Näheres dazu steht in den PRMs, aber leider sind dort meist nur BASIC-Beispiele aufgeführt. C und vor allem OSLib werden dort generell nicht behandelt.

Auf ein Ereignis muss immer reagiert werden. Nämlich wenn dem Programm gesagt wird, dass es beendet werden soll. Das soll grundsätzlich immer vom Taskmanager aus funktionieren. In diesem Fall sendet der Taskmanager über die WIMP eine Nachricht an das Programm mit dem Inhalt, dass es beendet werden soll.

Die WIMP verfügt dazu über ein umfangreiches Nachrichtensystem. RISC OS kann nicht nur die einzelnen Programme über aufgetretene Ereignisse informieren, sondern von den einzelnen Programmen auch Nachrichten entgegennehmen und an andere Programme weiterreichen. Dies wird auch über Ereignisse gesteuert. Das Beenden eines Programmes wird über das Ereignis User_Message oder User_Message_Recorded gesendet. Für beide Ereignisse gibt es eine Vielzahl von Nachrichten. Die Informationen zu den vorhandenen Ereignissen oder Nachrichten für das Programm werden in einen vorher zu reservierenden Datenblock geschrieben.

Ein kooperatives Multitasking-Programm für RISC OS soll nun im wesentlichen Kern immer eine zentrale Poll-Schleife durchlaufen, in welcher es auf die Ereignisse reagieren kann. Im folgenden Programm wird das über die While-Schleife erledigt, die beendigt wird, wenn das Ereignis Beenden auftritt. Dann wird das Programm beendet.

   #include "oslib/wimp.h"
   #include <stdbool.h>

   int main()
   {
     wimp_version_no version_out;
     wimp_t task_handle;
     wimp_event_no event;
     wimp_poll_flags mask = 1;
     wimp_block block;
     osbool quit_pending = FALSE;

     task_handle = wimp_initialise(310, "OSLib_Example 3", NULL, &version_out);
     while(!quit_pending) {
       event = wimp_poll(mask, &block, NULL);
       switch(event) {
         case wimp_USER_MESSAGE:
         case wimp_USER_MESSAGE_RECORDED:
           if(block.message.action == message_QUIT) {
             quit_pending = TRUE;
             break;
           }
       }
     }
     wimp_close_down(task_handle);

     return 0;
   }
							

Hier gibt es aber noch ein kleines Problem. Vielen Programmen ist es egal, ob nun gerade der Mauszeiger über das eigene Fenster geschoben wurde oder eine Datei auf das Programmsymbol auf der Iconbar (Symbolleiste) gezogen wurde. Aber für RISC OS sind das Ereignisse, die an das Programm übergeben werden müssen. Im Programm wird dann entschieden was mit dem Ereignis passiert. Bei Desinteresse wird die Rechenzeit wieder abgegeben. Sehr viele Programme warten zum Beispiel nur auf einen Klick auf OK um tätig zu werden. Jedes andere Ereignis sind für diese Programme sinnlose Ereignisse, deren Mitteilung und Verarbeitung kostet Zeit und verlangsamen das gesamte System. Besonders wenn viele Programme gerade am laufen sind die auf jedes Ereignis horschen, aber nicht alle nutzen. Ausnahme ist natürlich immer das Ereignis Beenden.

Insbesondere das Ereignis No Reason bremst in vielen Programmen unnötig den Rechner aus. Mit No Reason möchte RISC OS dem Programm Zeit für Hintergrundarbeit geben. Eine gute Sache, aber wie schon geschrieben, warten viele Programme auf Benutzereingaben bevor es Rechenzeit benötigt. Besser ist es, wenn man im Programm RISC OS mitteilt auf welche Ereignisse das Programm reagieren möchte. Dann müsste RISC OS zum Beispiel das Ereignis Mauszeiger verlässt Programmfenster gar nicht mehr dem Programm mitteilen. Das würde das System insgesamt etwas schneller machen.

Mit dem SWI Wimp_Poll kann man RISC OS mitteilen, auf welche Ereignisse das Programm reagieren möchte und auf welche nicht. Dies wird über den ersten Parameter von wimp_poll() gemacht und heiß in den Beispielprogrammen mask. Im ersten Parameter wird eine 32 Bit Zahl übergeben. Die einzeln Bits der Zahl stehen für die Ereignisse. Theoretisch sind damit 32 Ereignisse möglich. Real werden aber weniger von RISC OS genutzt. Ist ein Bit gesetzt, dann möchte das Programm das jeweilige Ereignis nicht behandeln. Im Programm oben steht in der Variablen mask eine eins. Damit ist das Bit Null auf eins gesetzt. Das bedeutet, dass das Programm an das Ereignis No Reason nicht interessiert ist und damit keine Hintergrundarbeit leisten möchte. Das Betriebssystem RISC OS wird damit dem Programm keine Zeit für Hintergrundarbeit bereitstellen.

TaskUsage Das ist der Grund warum OSLib_Example 2 sich nicht quasi direkt nach dem Start beendet. Wenn man den Wert von mask auf 0 setzt, wird das Programm nur einen Augenblick lang laufen. Wird bei OSLib_Example 3 mask auf 0 gesetzt, passiert augenscheinlich nichts. Mit Programmen wie zum Beispiel TaskUsage sieht man dann, dass die Variante mit der Null mehr Prozessorleistung verbraucht. Auch wenn die Unterschiede gering sind, summiert sich das Problem mit jedem Programm das unnötigerweise das Ereignis No Reason erhält. Aus diesen Grund ist in der Downloadversion von OSLib_Example 3 der Wert der Pollmaske nicht eins und erlaubt nur das Beenden.

Man sollte also dieses Bit in der Regel immer setzen. Programme die langwierige Arbeit verrichten müssen, sollten im Hintergrund laufen. Zusätzlich gibt es Programme, die im Hintergrund auf etwas warten oder nur in Zeitabständen aktiv werden. Solche Programme müssen dann etwas anders agieren als hier beschrieben und bei denen wird man das No Reason Bit nicht setzen. Mehr dazu gibt es im Artikel Multitaskingprogrammierung unter RISC OS. Die dort gezeigten Programme laufen unter BASIC, können aber auch in C übertragen werden.

Bits Die Erstellung der Maske, auf welche Ereignisse das Programm reagieren möchte, ist umständlich und man neigt dazu dabei Fehler zu machen. Um das zu vereinfachen gibt es das Programm Bits von Philip Mellor. Wenn man das Programm gestartet und das Fenster geöffnet hat, muss man zuerst PollMasks auswählen. Das kann man mit einem Klick auf die Statuszeile unten wo IconFlags steht und dann mit der Auswahl von PollMasks im Menü erreichen. In der Statuszeile steht dann, wie im Bild zu sehen, PollMasks. Im Fensters gibt es eine Reihe von kleinen unbeschrifteten Schaltflächen. Wenn man mit dem Mauszeiger über die Schaltflächen fährt, steht in der Statuszeile die Bitnummer und eine kurze Beschreibung. Dieses Verhalten ist nebenbei ein schönes Beispiel für Ereignisse unter RISC OS. Mit einen Klick auf die Schaltflächern kann man dann die Pollmaske erstellen. Mit Hilfe des PRM (3-117) oder der StrongHelp Hilfe Wimp (Wimp / Poll / mask) kann man die Bedeutung nachlesen. Links oben im Fenster kann man dann den Wert als Hex- oder Dezimalzahl sehen. Das Zahlensystem kann man mit einen Klick auf Hex beziehungsweise Dec wechseln. Wenn man im Editor mit dem Cursor an die richtige Stelle im C Programmtext geht, kann man mit einem Klick auf Insert den Maskenwert in das Programm eintragen. Bits ist ein Werkzeug, das auch für andere Dinge bei der Programmierung nützlich ist.

Das Programm OSLib_Example 3 ist immer noch ein Programm ohne Funktion, ist aber ein Multitaskingprogramm das geduldig darauf wartet beendet zu werden. Dies ist für zukünftige WIMP-Programme schon eine gute Basis.

 
Weiter geht es im sechsten Teil mit der Erzeugung von Fenstern.

Einen Fehler im Artikel gefunden, etwas unklar, Ergänzung oder ein Tipp? Einfach eine Nachricht schicken!

Name: *

EMail:

Text: *
Hardware   Software   Praxis   Sonstiges  
ArcSite   News   Magazin   Börse   Links   ArcArchie   Homepages