Vision
Während meiner Tätigkeit als Softwareentwickler habe ich ein Werkzeug eingesetzt, das aus UML-Modellen Code generierte. Diesem Werkzeug war ein Framework mitgegeben, auf das der generierte Code zugreifen konnte. Dieses Framework konnte die Software in mehreren Threads ausführen, die aber alle demselben Prozess angehörten und denselben Speicher nutzten.
Daher habe ich darüber nachgedacht, wie ein solches Framework wohl aussehen müsste, wenn es in mehreren Prozessen mit getrenntem Speicher laufen würde.
micro-kernel mit object execution framework
Das object execution framework beinhaltet eine Basisklasse für eine Zustandsmaschine, die über eine message queue verfügt. Auf diese Weise lässt sich ein kooperatives Multitasking implementieren.
Kooperatives Multitasking hat die folgenden Vorteile:
- Sequentieller Zugriff auf den Speicher
Da die Zustandsmaschinen alle im selben Thread laufen gibt es keine race conditions, bei denen mehrere Threads zugleich auf dieselben Adressen im Speicher zugreifen. Diese race conditions sind der große Nachteil des multithreading. Ihnen wird mit mutexes abgeholfen, die den gleichzeitigen Zugriff sequenzieren. Das wiederum birgt das Risiko von deadlocks. - run to completion
run to completion bedeutet, dass der Kontrollfluss die Zustandsmaschine erst dann verlässt, wenn eine Aufgabe zu Ende geführt wurde. Beim multithreading wird er dagegen immer dann unterbrochen, wenn der kernel den thread wechselt. Diese Wechsel kosten aber viel Rechenzeit. Das kooperative Mulititasking hat keine solchen Wechsel und spart diese Rechenzeit ein.
Das kooperative Multitasking kann allerdings keine Aufgaben priorisieren. Dafür braucht es ein Betriebssystem mit Prozessen unterschiedlicher Priorität. Das Wechseln von Prozessen nennt man präemptives Multitasking. Die Herausforderung dabei ist, die Prioritäten der Prozesse festzulegen. Nach welchen Kriterien soll man das tun?
Was wäre aber, wenn die Prozesse keine festgelegten Prioritäten hätten, sondern die Aufgaben, die in Form von messages an die Zustandsmaschinen vergeben werden, die in den Prozessen laufen? So gesehen hätten die messages Prioritäten. Diese festzulegen wäre viel leichter, denn sie ließen sich aus den Aufgaben ableiten.
Am einfachsten ist es, wenn man diesen messages deadlines zuweist, also Fristen, bis zu deren Ablauf die Aufgabe zu Ende geführt sein muss. Die Priorität eines Prozesses wäre dann die früheste deadline in seiner message queue.
Diesen Algorithmus gibt es bereits. Er heißt earliest deadline first (EDF).
Die Vision ist also ein micro kernel mit einem object execution model als Programmierschnittstelle, um mit einem UML Werkzeug Code zu generieren, der auf Prozessen unterschiedlicher Priorität läuft, die von den deadlines der messages abhängen, die die Zustandsmaschinen des object execution model einander senden. Diese messages wären die einzigen Daten, die zwischen den Prozessen ausgetauscht würden. Der gleichzeitige Zugriff auf geteilte Speicheradressen fände also nur durch den kernel statt. Der Programmierer müsste sich nicht damit auseinandersetzen.