mikrocontroller.net

Forum: Projekte & Code Multithreading auf LPC800 - 86Byte(!) Code-Groesse


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Marc P. (marcvonwindscooting)
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Hallo Leute,

ich will hier einen extrem schlanken Ansatz f"ur ARM-Prozessoren im 
THUMB-Modus (Cortex-M0, Cortex-M3, ARM4TDMI Thumb) vorstellen, mit dem 
man richtiges Kontext-Umschalten zwischen Threads durchf"uhren kann. 
Also keine 'armer Mann' Implementierung. Kooperatives Multitasking.

Ich habe es erst k"urzlich auf dem Cortex-M0 portiert, nachdem ich es 
auf dem ARM7TDMI schon eine Weile in Programmen (ARM-Modus) benutze.
Die Threads m"ussen eine wichtige Bedingung erf"ullen: ihre 'main()' 
darf nie zur"uckkehren - daher der Name Thread-Loop, tl - damit man 
immer daran erinnert wird.

tl.h sind die C-Funktionsprototypen und die Context-Datenstruktur.
tl.s ist die Implementierung in Thumb2-Code.

multitask.c ist ein Beispielprogramm, mit ein paar Threads und einer 
m"oglichen Implementierung von sleep().

Es gibt keine Synchronisationsprimitiven (mutexe, semaphore, 
Event-Schlangen). Auf einem M0 steht man da n"amlich ziemlich im Regen - 
er hat keine Befehle daf"ur. Ausserdem ist in tl gar kein Scheduler 
drin - das w"are mit eine zu starke Verflechtung in die Hardware. tl 
erlaubt eine "Anderung der Programmstruktur, es zwingt nicht zu einer 
totalen Ver"anderung.

Ein Thread ist eine Funktion vom Typ TlLoop, d.h. eine void-Funktion, 
die einen (TlContext*)-Thread-Kontext als Argument hat und explizit nie 
zur"uckkehrt.
Tats"achlich kehrt die Funktion schon immer wieder kurzzeitig zur"uck 
und zwar an den Stellen, an denen sie tlYield() aufruft. Sie ist sogar 
verpflichtet tlYield() immer wieder aufzurufen, nachdem sie eine 
Kleinigkeit getan hat.

Ein richtiger Thread hat einen eigenen Stack. F"ur die Erzeugung dieses 
Stacks (RAM-Speicherbereich mit 8-bit alignment) ist der Programmierer 
verantwortlich. Er kann diesen sogar auf dem main()-Stack lokal anlegen. 
Der Stack (genauer: der initiale Stackpointer) ist in der 
TlContext-Struktur einzutragen. Vorsicht: der Stacks wachsen auf 
Cortex-M-Cores nach unten, d.h. in TlContext muss die Speicherstelle 
unmittelbar hinter dem f"ur den Stack reservierten Speicherbereich 
eingetragen werden.
Ist der Stackpointer eingetragen, kann mit tlCreate() dem Thread 'Leben' 
eingehaucht werden. tlCreate() kehrt zum Aufrufer zur"uck, sobald die 
Thread-Funktion das erste mal tlYield() aufruft. Beliebig viele weitere 
Threads k"onnen so - mit jeweils eigenen Stacks - erzeugt werden.

Ein Thread kann bis zu seinem n"achsten tlYield() weiterlaufen lassen 
durch einen Aufruf von tlCall() mit seinem Kontext.
Welcher Thread wann laufen darf, das bleibt dem Programmierer 
"uberlassen.
Ein Thread kann auch durch eine Interrupt-Routine weiterlaufen, 
nachdem er von main() mit tlCreate() erzeugt wurde und tlCreate() zu 
main zur"uckgekehrt ist.

Es gibt keine Funktion zum Beenden eines Thread. Man ruft ihn einfach 
nicht mehr auf. Und wenn man ihn nicht mehr aufruft, kann man auch 
seinen Stack recyclen.

Das Beispielprogramm multitask zeigt das alles exemplarisch. Es ist 
nicht f"ur eure Entwicklungsumgebungen gemacht, es basiert auf meiner 
c-lpc8 Bibliothek. Diese habe ich noch nicht ver"offentlicht (Jan 2014). 
tl ist vielmehr ein Teil derselben, f"ur den ich besonderen 
Ver"offentlichungsdrang versp"ure.

tl ist vermutlich nicht einsetzbar unter ucLinux oder "ahnlichem, da 
ich das Register R12 (IP) nicht sichere, d.h. Zielplattform ist 'bare 
metal' aka 'freestanding'.

Bitte kommt nicht auf die Idee, den wenigen Assembler-Code als 
inline-Assembler zu schreiben und die Funktion zu 'inlinen' - das geht 
m"achtig in die Hose! Keine der Funktionen darf inline sein oder 
(unabsichtlich) inline werden, denn sie verlassen sich alle auf den 
Inhalt von R14 (LR).

Ja, man k"onnte TlContext auf einen einzigen Pointer reduzieren. Aber so 
wie's jetzt ist, sind die Aufgaben der Felder menschenverst"andlicher.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.