Kategorien
Honor Technology Micropython / Pico

Multi – Threading

Da der Raspberry Pi Pico zwei Kerne hat, kann man Aufgaben auf diese beiden Kerne verteilen, sodass sie gleichzeitig abgearbeitet werden. Mit dem Modul _thread kann das realisiert werden. Allerdings gibt es hier auch wichtige Dinge zu beachten.

Um Multicore – Programming zu betreiben, muss auf jeden Fall zuerst einmal das Modul _thread importiert werden.

Nehmen wir nun an, wir definieren zwei Funktionen. Beide sollen eine Dauerschleife haben.

Diese zwei Funktionen haben jeweils eine Dauerschleife. Einfach so gleichzeitig zu starten wäre also unmöglich. Das Programm würde zuerst die eine Schleife starten wollen und danach die andere. Da es bereits bei der ersten Schleife in einen Dauerschleifen-Zustand läuft, wird es diese Schleife nie verlassen und somit auch den Start der zweiten Schleife nie erreichen.

Um diese beiden Funktionen nun gleichzeitig ablaufen zu lassen, muss eine von ihnen auf den zweiten Thread ausgelagert werden. Die andere kann ganz normal vom Main-Thread (auf dem man sich grundsätzlich immer befindet) gestartet werden. Da ein Programm grundsätzlich immer auf dem Main-Thread gestartet wird, muss nun zuerst die Schleife, die parallel laufen soll, gestartet werden.

Diese Anweisung startet nun funktionEins auf einem nebenläufigen Thread.
Man schreibt hier nur die Funktionssignatur als erstes Argument.
Eventuelle Parameter, die der Funktion mitgegeben werden müssen, schreibt man nach dem Komma als zweites Argument.
Da unsere Funktion keine Parameter hat, schreiben wir hier einfach ().

Nun können wir funktionZwei ganz normal wie gewohnt starten. Direkt nach der Anweisung zum Start von funktionEins.

Mit diesem gewöhnlichen Aufruf starten wir jetzt auf dem Main-Thread funktionZwei. Ab jetzt laufen alle beide Dauerschleifen auf den zwei Kernen parallel.

Das funktioniert im Grunde schonmal. Allerdings würde jetzt beim Beenden des Programms nur der Main-Thread beendet. Der parallele Thread läuft dagegen weiter und macht den Pico ‚Funktionsunfähig‘. Der Pico kann nun nicht mehr speichern und das Programm auch nicht mehr gestartet werden. Es hilft nur noch abstecken, wieder anstecken und neu starten.

Das Gefährliche daran ist vor allem, dass wenn man den Pico im Stand-Alone-Modus hat – also wenn er sofort losläuft, sobald er Strom bekommt – kommt man aus dieser Falle nur noch schwer heraus.

Es braucht praktisch einen Mechanismus, der den nebenläufigen Thread beendet, wenn man das Programm beendet – und bevor der Main-Thread beendet wird.

Eine Möglichkeit ist es, eine Flag-Variable zu benutzen, auf die der nebenläufige Thread hört, anstatt nur auf Dauerschleife zu laufen.

Hier farbig hervorgehoben, kommt nun global ein Bool hinzu namens flag. Und die Funktion führt ihre Schleife nun nur solange aus, solange die flag True ist.

Diese Flag muss nun gesteuert werden. Und das soll funktionZwei auf dem Main-Thread übernehmen.

funktionZwei greift nun auf die globale Variable flag zu. In der Schleife bauen wir einen try - except Block ein. except KeyboardInterrupt passiert also nun, wenn das Programm mit <Ctl><C> beendet wird. Wenn dieses Ereignis eintritt, schaltet funktionZwei nun also die flag auf False, was dazu führt, dass auch die Schleife von funktionEins verlassen wird.

Als letzte Vorsichtsmaßnahme kann jetzt noch dafür gesorgt werden, dass funktionEins und funktionZwei nicht gleichzeitig auf flag zugreifen wollen.
Dazu benötigen wir ein ‚Schloss‘ das, solange funktionZwei auf die Variable zugreift, für funktionEins geschlossen bleibt.
So etwas stellt das Modul _thread auch zur Verfügung.

funktionZwei sperrt den Zugang auf flag für funktionEins, solange sie selbst darauf zugreift. funktionEins muss warten, bis schloss wieder „auf ist“.

Zum Schluss hier noch einmal das Listing als Ganzes:

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert