Inhalt

• Antrieb Abtrennung der Steuerlogik
• Hilfs­mittel Wie hilft mir Ada?
• Kodierung Wie geht es weiter?
• Test Funktioniert es denn auch?
• Quell­code Zum Weitermachen
• Com­piler Das perfekte Werkzeug
• Lite­ratur Das gute, alte Buch


An­trieb

Trennung von Steuerlogik und Funktionalität

Wenn das Projekt ein Langläufer ist, wer­den da­durch auch har­te Rah­men­be­din­gungen ge­setzt, et­wa die (fast) aus­schließ­li­che Ver­wen­dung der Pro­gram­mier­spravche Ada der Aus­bau­stufe 1995. Ada hat sich aber sehr harmonisch wei­ter ent­wi­ckelt, es gibt den Sprach­standard 2005 und 2012. Da sollte man sich doch ein we­nig im neu­en Ter­rain umschauen ...

In einem Programmsystem gibt es meist mehr oder we­ni­ger vie­le Ak­ti­vi­tä­ten, die pe­rio­disch aus­ge­führt werden müssen, so etwa das Aus­le­sen und Aus­wer­ten von Sen­sor­da­ten. Und meist gibt es ver­schie­de­ne Be­triebs­mo­di, in de­nen etwa die Sensorda­ten un­ter­schied­lich oft au­sge­le­sen wer­den müssen.

Es liegt nahe, die periodischen Aktivitäten durch ne­ben­läu­fi­ge Ada-Tasks abzubilden, deren Rumpf ty­pi­scher­wei­se wie folgt auf­ge­baut ist: In der Zeile 135 wird eine absolute Zeit Next_Time berechnet und in der Zei­le 136 wird dann mittel delay until gewartet, bis die Zeit zur Aus­füh­rung der Aktivität in Zeile 138 gekommen ist.

Eine mit 'delay until' zeitgesteuerte Task

So weit, so gut. Die Aktivität wird durch ein ak­ti­ves Objekt im­ple­men­tiert, welches war­ten kann - wie lange gewartet wer­den soll, ist der Ak­ti­vi­tät aber egal. Die Berech­nung der War­te­zeit hat in dem ak­ti­ven Objekt ei­gent­lich nichts zu su­chen.

Und was wäre wenn sich die Periode, hier Sto­ra­ge_Du­ra­tion, bei einem Mo­dus­wech­sel ändert? Ei­gent­lich ent­stünde kein großartiges Problem, aber das aktive Ob­jekt würde mit weiterer, noch mehr Steu­er­lo­gik be­frach­tet. Eine häß­liche Sache - finde ich.

Was ist zu tun? Wir trennen die Steuerung des Ab­lauf­ver­hal­tens von der aus­zu­füh­ren­den Auf­ga­be! Der obi­ge Task-Rumpf müsste etwa wie das fol­gen­de Muster aus­se­hen: Mittels der Zei­le 19 wird die Task nach Wunsch blo­ckiert, Ein­zel­hei­ten in­te­res­sie­ren hier nicht, die aus­zu­füh­ren­de Auf­ga­be wird durch ei­ne Prozedur im­ple­men­tiert, die in Zeile 21 auf­ge­ru­fen wird. Wunderbar und schlicht und schön.

Die Details der Zeitsteuerung sind ausgelagert!



Hilfs­mit­tel

Wie hilft mir die Programmiersprache?

Schon Ada95 definiert im Anhang C System Pro­gram­ming zwei Pakete, die hier Ver­wen­dung fin­den können:

  • Ada.Task_Identification
  • Ada.Task_Attributes

Das Paket Task_Identification erlaubt es, exis­tie­ren­de Tasks zu iden­ti­fi­zie­ren, um sie etwa ab­zu­schießen:

Paketkopf Ada.Task_Identification (Ada2012)

Das generische Paket Task_Attributes gibt dem Pro­gram­mie­rer die Mög­lich­keit, durch Aus­prä­gen die­ses Pa­ke­tes be­lie­bi­ge nut­zer­de­fi­nier­te Daten an iden­ti­fi­zier­te Tasks zu binden - und zwar mit­hilfe der Pro­ze­dur Set_Value, mit­hilfe der Prozedur Va­lue können diese Daten dann wie­der aus­ge­le­sen wer­den.

Paketkopf Ada.Task_Attributes (Ada2012)

Es liegt nahe, dieses Paket zu verwenden, um den pe­rio­di­schen Tasks ihr gewünschtes Zeit­ver­hal­ten an­zu­hef­ten.

Weiter verwende ich die neue Mög­lich­keit, Tasks mit Sprach­mit­teln CPU-Ker­ne zuzuordnen zu kön­nen, und zwar über das Ada­2012-Paket Mul­ti­pro­ces­sors (Mps):

  • System.Multiprocessors

Paketkopf System.Multiprocessors (Ada2012)



Kodie­rung

Wie geht es weiter?

Die periodischen Aktivitäten werden über ei­nen Task-Typ im­ple­men­tiert. Es wird ex­pli­zit ein Ein­gang Start spendiert. Für je­des Task-Objekt wer­den als Dis­kri­mi­nan­ten über­ge­ben

  • ein Zeiger auf die Prozedur Tasked_­Procedure_­Access,
  • die Priorität der Task und
  • der CPU-Kern, auf dem die Task aus­ge­führt wer­den soll.

Die periodischen Tasks als Task-Typ

Die Perioden und die nächsten 'Ab­fahrts­zei­ten' der Task-Ob­jek­te wer­den über einen Verbund- oder Re­kord­typen Task_­In­for­ma­tion_­Record_­Type zu­sam­men­ge­fasst (Zeilen 9-14), mit dem auch gleich ei­ne Aus­prä­gung des Ada-­Pa­ke­tes Ada.­Task_­At­tri­bu­tes zur Pa­ket­in­stanz Pe­rio­dic_­Task_­Attributes vor­ge­nom­men wird (Zeilen 20-22).

Scheduling-Informationen und Paketinstanz

Schnitt­stelle I

Die engere Anwendungs­schnitt­stelle für ein ein­zel­nes pe­rio­di­sches Task­objekt liefert das Pa­ket Pe­rio­dic_­Task_­Sche­du­ler. Es wäre na­tür­lich wün­schens­wert, alle pe­rio­di­schen Tasks gleich als Ver­band an­spre­chen zu kön­nen - ein näch­ster Schritt zu einem wirk­li­chen Bau­stein.

Paketkopf Periodic_Task_Scheduler

Mit Set_Characteristic (Zeilen 11-14) wer­den ei­ner be­kann­ten Task die Sche­du­ling-Da­ten mit­ge­teilt, mit Abort (Zeile 20) kann die Task hart be­en­det werden und mithilfe der blo­ckie­ren­den Pro­ze­dur Wait_­Un­til_­Next_­Schedule (Zei­le 16) kann eine Task fremdgesteuert auf ihre näch­ste Ab­fahrt­zeit warten.

Schnitt­stelle II

Die weitere Anwendungsschnittstelle ist noch ver­bes­se­rungs­wür­dig. Hier fasse ich im Paket Many_­Pe­rio­dic_­Tasks_­Template die rele­vanten Daten der pe­rio­di­schen Task zu ei­nem Ver­bund­typen zu­sam­men:

Alles zusammengepackt!

Alle periodischen Tasks können nun in einem Rutsch ver­wal­tet werden - ein Beispiel:

Lohn der Mühe



Test

Ja, funktioniert es denn auch?

Es hat den Anschein. Ich habe zwei Test­pro­gram­me spen­diert, ei­nes, pe­riodic_­task_­scheduler-­test­.adb, zum An­tes­ten der An­wen­dungs­schnitt­stel­le I und eines, pe­rio­dic_­wor­ker_­system-main­.adb, zum Antesten der An­wen­dungs­schnitt­stel­le II.

Hier läuft das zweite Testprogramm mit drei pe­rio­di­schen Tasks, die nur dumme Aus­ga­ben machen. Beim Mo­dus­wech­sel ver­tau­schen die Tasks 1 und 3 ihre Scheduling-Zeiten - man sieht die Wirkung ...

Das ultimative Testergebnis

Zur weiteren Analyse könnte ich mein groß­ar­ti­ges Logs_­To_­Ram ver­wenden :-)



Quell­code

Hinweis: Die Zeilennummern stimmen nicht un­be­dingt mit denen in den obi­gen Code-Aus­schnit­ten überein.

•  Der Quellcode, gezippt     Mein GNAT-Projekt zum Weiter­machen



Ada-Com­piler

•  GNAT-Ada-Compiler        von AdaCore



Lite­ratur

Das gute, alte Buch

John Barnes
Programming in Ada 2005
Addison-Wesley, 2006

Alan Burns, Andy Wellings
Concurrent and Real-Time Programming in Ada 2005
Cambridge University Press, 2007

Dank an die beiden Herren!

Norman H. Cohen
Ada as a second language - based on Ada 95
The McGraw-Hill Companies, 1996