Guten Abend,
ich lese im Moment das Buch Software Engineering von Ian Sommerville
(Auflage 10).
Im Kapitel 21 wird auf das Thema "Entwicklung von Echtzeitsoftware"
eingegangen.
Dabei werden drei Echzeit-Pattern vorgestellt:
Observe and React
Environmental Control
Process Pipeline
Meine Frage dazu ist, ob es ein Buch gibt, dass weitere Pattern im
Architekturkontext vorstellt und diese in C bzw. C++ umsetzt?
Danke im Voraus
Andre
Eric B. schrieb:> Es gibt eine Reihe von 4 Büchern:> "Pattern-Oriented Software Architecture", Ausgegeben von Wiley.> Amazon is your friend :-)
Danke für den Vorschlag Eric, werde mir das Buch mal anschauen.
Btw. endlich mal was anders als "google is your buddy"..;)
Dirk K. schrieb:> Geht es dir nur um Echtzeit-Patterns?
Genau Dirk, hauptsächlich geht es mir um Architekturen im Embedded
Bereich. Denke die Zeiten in denen noch mit einer "Main Control Loop"
versucht wurde solche Systeme zum Laufen zu bekommen, sollten lange
vorbei sein. Ich würde gerne wissen welche Strategien da "State of the
Art" sind? (mir ist klar, das solche Entscheidungen von vielen Faktoren
abhängen und es nicht "Die Antwort" gibt)
Andre schrieb:> Ich denke die Zeiten in denen noch mit einer "Main Control Loop"> versucht wurde solche Systeme zum Laufen zu bekommen, sollten lange> vorbei sein. Ich würde gerne wissen welche Strategien da "State of the> Art" sind?
Warum denkst du das? Main Control Loop ist immer noch State of the Art.
An den Grundlagen der Softwareentwicklung hat sich in den letzten 40
jahren wenig geändert.
Bei Geräten mich reichlich Speicher setzt man hingegen oft auf eine RTOS
Variante.
Speziell Literatur zu Echtzeit-Pattern kenne ich nicht.
Ich kann dir noch die Gang of Four empfehlen, das ist
das Standardwerk schlechthin:
https://www.amazon.com/-/de/dp/0201633612
Es enthält die wichtigsten Pattern, die einem bei der
Software-Entwicklung weiterhelfen.
merciless
Stefan F. schrieb:> Warum denkst du das? Main Control Loop ist immer noch State of the Art.> An den Grundlagen der Softwareentwicklung hat sich in den letzten 40> jahren wenig geändert.>> Bei Geräten mich reichlich Speicher setzt man hingegen oft auf eine RTOS> Variante.
Klar, wenn man in einem Projekt Hardware verwenden muss, auf die kein
RTOS passt und man froh ist, dass man die eigentliche Funktionalität
irgendwie auf den µC bekommt, dann bewegt man sich innerhalb der
Rahmenbedingungen die das Projekt vorgibt.
Verwendet man jedoch Hardware worauf ein RTOS wie FreeRTOS, VxWorks,
oder RTLinux passt, sollte man das verwenden.
Dabei ist die Frage wie organisiert man Threads,Task und Prozesse, gibt
es dazu Strategien?
Zum Punkt in den letzten 40 Jahren hat sich nicht dazu getan.
Da bin ich anderer Meinung:
Ein Punkt ist die IOT Entwicklung, die eine ganze Branche hervorgebracht
hat.
Hier wird zB. von Amazon auch in diversen Produkten FreeRTOS verwendet.
Bei Google Produkten ist es ähnlich mit dem Android Things.
Bei solchen Unternehmen kann ich mir nicht vorstellen, dass ohne
Architekturen oder Vorgaben gearbeitet wird.
Dirk K. schrieb:> Ich kann dir noch die Gang of Four empfehlen, das ist> das Standardwerk schlechthin:
Ok, danke.
Stefan F. schrieb:> Warum denkst du das? Main Control Loop ist immer noch State of the Art.
Oh Gott! Hoffentlich nur bei 8bittern.
> An den Grundlagen der Softwareentwicklung hat sich in den letzten 40> jahren wenig geändert.
Nur bei dir nicht.
> Bei Geräten mich reichlich Speicher setzt man hingegen oft auf eine RTOS> Variante.
Reichlich Speicher? Ich hatte 20KB SRAM und 128KB Flash (STM32F103).
Gebraucht habe ich 12KB SRAM und ca. 60KB Flash. Benutzt haben wir
embOS. Nein, kein Hobbygedöns, sondern Weisse Ware.
20kB RAM ist für ein RTOS reichlich.
Es wird wohl nicht mehr lange dauern, bis wir uns keinen Kopf mehr um
Speicherbedarf machen müssen. Bei der PC Programmierung ist das ja schon
längst der Fall für 90% aller Anwendungen. Die Mikrocontroller holen
auch spürbar auf.
Stefan F. schrieb:> Es wird wohl nicht mehr lange dauern, bis wir uns keinen Kopf mehr um> Speicherbedarf machen müssen. Bei der PC Programmierung ist das ja schon> längst der Fall für 90% aller Anwendungen. Die Mikrocontroller holen> auch spürbar auf.
Ja. Das geht dann wieder so, wie es auch bei der Performance lief: alle
Fortschritte der Hardware wurden unverzüglich durch Faulheit/Dummheit
der Programmierer wieder aufgefressen.
Es ist also nur eine Frage der Zeit, bis auch das simpelste "Hello
world" 128GB RAM benötigen wird durch 'zich Trillarden Schichten absolut
bekloppter Frameworks und Libs, die völlig unkritisch benutzt werden,
weil man ja das Rad nicht neu erfinden will...
Nicht auszudenken, was heutige Computer leisten könnten, wenn wirklich
fähige Programmierer den Code dafür schreiben würden...
c-hater schrieb:> Es ist also nur eine Frage der Zeit, bis auch das simpelste "Hello> world" 128GB RAM benötigen wird durch 'zich Trillarden Schichten absolut> bekloppter Frameworks und Libs, die völlig unkritisch benutzt werden,> weil man ja das Rad nicht neu erfinden will...>> Nicht auszudenken, was heutige Computer leisten könnten, wenn wirklich> fähige Programmierer den Code dafür schreiben würden...
Gehört zwar nicht zum Thema, eher zum Software Engineering, aber gut.
Viele Techniken haben Ihren Sinn. Wir haben nicht mehr die 1970 wo
einzelne Genies an einem Projekt oder System alles alleine entwickeln.
Projekt werden grösser, umfangreicher und komplexer wozu nur mal auch
ganze Teams nötig sind. Diese Teams müssen organisiert werden, dazu
können bestimmte Vorgehen wie auch Tools helfen diesen Umfang und
Komplexität zu beherrschen.
Wenn jeder in der Main Loop ändert, am besten noch ohne Source Control
und ohne mit anderen zu sprechen, muss man sich über bestimmte Effekte
nicht wundern.
Selbst in der Raumfahrt wo die Koryphäen der verschiedenen Fachgebiete
arbeiten, müssen sich an bestimmte Regeln halten werden. Bei der ESA ist
das der ECSS (European Cooperation for Space Standardisation) oder bei
NASA das EPPD (Engineering Policy, Practice and Development Division).
c-hater schrieb:> Stefan F. schrieb:>>> Es wird wohl nicht mehr lange dauern, bis wir uns>> keinen Kopf mehr um Speicherbedarf machen müssen.>> Bei der PC Programmierung ist das ja schon längst der>> Fall für 90% aller Anwendungen. Die Mikrocontroller>> holen auch spürbar auf.>> Ja. Das geht dann wieder so, wie es auch bei der> Performance lief: alle Fortschritte der Hardware> wurden unverzüglich durch Faulheit/Dummheit der> Programmierer wieder aufgefressen.
Durch nichts wird deutlicher, dass Du von der Arbeit
des durchschnittlichen Programmierers keine Ahnung
hast, als durch diese Einlassungen.
> Nicht auszudenken, was heutige Computer leisten> könnten, wenn wirklich fähige Programmierer den> Code dafür schreiben würden...
Das Problem sind weniger die Programmierer, sondern
vielmehr...
1. die Chefs, die den Kunden das Blaue vom Himmel
versprechen und die Programmierer entsprechend in
die Mangel nehmen,
2. die Kunden, die sich an die Dumpingpreise gewöhnt
haben und jegliche moderne Elektronik als Wegwerf-
ware auffassen, die nichts wert ist,
3. die Erfinder "neuer" Programmiersprachen, denen
das Erfinden "neuer" trendiger Sprachen offenbar
wichtiger ist als das Verbessern und Vereinfachen
bereits bekannter Ideen.
Andre schrieb:> Projekt werden grösser, umfangreicher und komplexer> wozu nur mal auch ganze Teams nötig sind. Diese> Teams müssen organisiert werden, dazu können> bestimmte Vorgehen wie auch Tools helfen diesen> Umfang und Komplexität zu beherrschen.> Wenn jeder in der Main Loop ändert, am besten noch> ohne Source Control und ohne mit anderen zu sprechen,> muss man sich über bestimmte Effekte nicht wundern.
Das ist zwar sachlich richtig -- nur hat das absolut
nichts damit zu tun, ob man eine Mainloop verwendet
oder nicht.
Wenn man auf den Satz von Böhm und Jacopini zurückgeht,
dann kann man sich überlegen, dass für eine Laufzeit-
garantie nur die Schleifen kritisch sind, denn sie
erfordern Rücksprünge.
Anders ausgedrückt: Durch Schleifen (=Rücksprünge)
entstehen parasitäre Zustände, in denen der Prozessor
beliebig lange verweilen kann -- die also die weitere
Ausführung blockieren können.
Dieses Problem wird durch die Technik der Hauptschleife
schon im Ansatz vermieden; "lokale Schleifen" entarten
hier zu reinen bedingten Anweisungen, die quasi-parallel
ablaufen können, weil in jedem Durchlauf der Hauptschleife
immer nur entschieden werden muss, ob in der "lokalen
Schleife" eine weitere Iteration auszuführen ist oder
nicht.
Das Problem liegt nur darin, dass keine der üblichen
Programmiersprachen eine solche Sichtweise unterstützt,
und daran wird sich wohl auch nichts mehr ändern.
Die euklidische Geometrie, die über 2000 Jahre alt ist,
wird immer noch verwendet -- aber was die Steuerungs-
techniker von vor 50 Jahren zu sagen hatten, ist ja
toootaaaaal veraltet...
Andre schrieb:> Ein Punkt ist die IOT Entwicklung,> die eine ganze Branche hervorgebracht hat.
Daran ist aber nicht die Entwicklung hunderttausender
Software-Frameworks schuld, sondern hauptsächlich:
- die Verfügbarkeit energiesparender Hardware
- mit hoher Leistungsfähigkeit und Funk
- sowie die dafür benötigte Infrastruktur
- mit lizenzfreiem oder günstigen Zugang.
Ohne flächendeckenden Zugang zum Internet gäbe es kein IoT.
Realistisch ist das erst durch flächendeckendes WLAN und 3G geworden
(denn dadurch wurde GSM erschwinglich und zugänglich). Schau dir mal die
Telefon- oder Mobilfunktarife von vor 10 oder 20 Jahren an.
Die dazu passende Softwarebranche ist erst daraus erwachsen.
Andre schrieb:> Wenn jeder in der Main Loop ändert, am besten noch ohne Source Control> und ohne mit anderen zu sprechen, muss man sich über bestimmte Effekte> nicht wundern.
Irgendwie verstehe ich gerade nicht, was "Programmcode" mit
"Arbeitsweise und Projektmanagement" zu tun hat. Modern strukturierten
Javascript-Hipstercode für Android kann ich auch ohne Versionierung
schreiben, und eine ordentlich gepflegte Main-Loop-Struktur in Git
pflegen.
Apropros Android: Wie groß ist inzwischen ein APK eines trivialen
Programmes, und wieviel Energie braucht man, um es auf einem modernen
Smartphone zu installieren? (Die Installation schiebt den Bytecode durch
einen Ahead-of-Time-Compiler, deswegen dauert so eine Installation seit
einigen Versionen deutlich länger.)
Egon D. schrieb:> Wenn man auf den Satz von Böhm und Jacopini zurückgeht,> dann kann man sich überlegen, dass für eine Laufzeit-> garantie nur die Schleifen kritisch sind, denn sie> erfordern Rücksprünge.
Komplexitätsbetrachtungen unterschlagen den konstanten Faktor. Es ist
zwar schön, wenn dein toller Algorithmus das Problem in O(1) lösen kann,
bringt aber trotzdem nicht, wenn er dann konstant "eine Woche" braucht.
Genau das ist ja das Problem, wenn man Komplexität über Komplexität über
Komplexität stapelt. Überlege dir mal, wie krass schnell ein Webbrowser
die Seiten rendern könnte, wenn er dafür keine 20.000
Javascript-Datenstruktur-Nodes in einer virtuellen Maschine durchnudeln
müsste.
Andre schrieb:> Selbst in der Raumfahrt wo die Koryphäen der verschiedenen Fachgebiete> arbeiten, müssen sich an bestimmte Regeln halten werden.
Solche Regeln betreffen aber weder den typischen Android-Entwickler noch
Google selbst, die Android entwickeln. Und ich garantiere dir, dass auf
dem durchschnittlichen Smartphone wesentlich mehr Code läuft, als auf
dem Space-Shuttle.
c-hater schrieb:> Nicht auszudenken, was heutige Computer leisten könnten, wenn wirklich> fähige Programmierer den Code dafür schreiben würden
Da ist sicher was dran. Aber auch eine Menge Übertreibung.
Zum Beispiel sind unsere Computer trotz dieses Fortschrittes kleiner und
billiger geworden. Außerdem können sie eine Menge mehr, als z.B. die
Geräte von vor 30 Jahren.
> Überlege dir mal, wie krass schnell ein Webbrowser> die Seiten rendern könnte, wenn er dafür keine 20.000> Javascript-Datenstruktur-Nodes in einer virtuellen Maschine durchnudeln> müsste.
Ich habe einen uralten Firefox 1.x mit einem aktuellen Firefox und einer
sehr großen plain HTML Seite (nur Text und Bilder) verglichen. Sowohl
Speicherbedarf als auch Performance sind fast gleich. Große
Verbesserungen gibt es jedoch beim Javascript, was verständlich ist,
denn das wird halt immer mehr benutzt und wurde daher optimiert.
So wie du kenne auch ich Programme, die tatsächlich sehr aufgebläht
wirken. Vor allem fällt mir das auf Smartphones immer wieder auf.
Diese ganzen Frameworks sind zweischneidige Schwerter. Sie ermöglichen
preisgünstige Entwicklung umfangreicher Programme. Auf der anderen Seite
erhöhen sie das Risiko, die Kontrolle über das Produkt zu verlieren.
Deswegen sind erfahrene Manager und Entwickler diesbezüglich
vorsichtiger geworden, als du es vielleicht noch vor 10 Jahren erlebt
hast. Einfach alles zusammen klatschen, was das Netz bietet, ist keine
Basis für ein stabiles Geschäft, das ist unter erfahrenen Leuten
bekannt.
Steigende Komplexität haben wir überall. Schau mal, was am BER passiert,
dort ist es außer Kontrolle geraten. Der veraltet links schon, während
man rechts die letzten Bauarbeiten abgeschlossen hat. Auch bei unseren
Autos wird von vielen Leuten zunehmend kritisiert, dass sie zu komplex
geworden sind. Andere wiederum freuen sich über die ganzen Konfort und
Sicherheits-Aspekte. Wer würde heute noch eine Ente oder einen R4
kaufen? Wohl fast niemand.
Wer würde heute noch mit einem PC unter Windows 3.0 arbeiten wollen?
Wohl auch kaum jemand. Erinnerst du dich noch an die zeit, wo man die
IDE beenden musste, um den Compiler laufen lassen zu können oder das
eigene Programm starten zu können? Ich will nicht zurück in die 90er!
Kennst du das Pareto Prinzip? Pareto sagt, dass man 80% vom Ziel mit 20%
Aufwand erreicht. Für den Rest braucht man 80% des Aufwandes. Wir
befinden uns gerade in dieser zweiten Phase - und zwar Permanent, weil
die Anforderungen fortlaufend erhöht werden.
Die großen anfänglichen Fortschritte der 70er bis 90er Jahre mit wenig
Aufwand wirst du im IT Bereich nicht mehr erleben. Wenn du dich danach
sehnst, dann schau nach einer neue Technologie aus, die gerade erst
geboren wurde. Quantenrechner sind ein heißer Kandidat.
Andre schrieb:> Denke die Zeiten in denen noch mit einer "Main Control Loop"> versucht wurde solche Systeme zum Laufen zu bekommen, sollten lange> vorbei sein.
Sind sie nicht immer. Wenn kleiner, billiger und stromsparender heute
genauso ausreicht wie vor 30 Jahren, dann macht man das auch so -
verbraucht dabei aber nur einen Bruchteil der Energie im Vergleich zu
früher und kann das sehr lange auf Batterie laufen lassen.
> Ich würde gerne wissen welche Strategien da "State of the> Art" sind?
Eine IMO sehr grundsätzliche Strategie ist "der Chef pennt, außer es
brennt". Ein Task mit sehr hoher Priorität wird fast immer schlafen,
aber dann aufwachen, wenn sofort reagiert werden muß, eben Echtzeit.
Andererseits bekommen Tasks, die kontinuierlich arbeiten, nur eine
geringe Priorität.
Gegen Ressourcen-Deadlocks vermeidet man erstens dynamische
Speicherallozierung, auch weil das unter der Haube effektiv Zustand
aufsammelt und nicht mehr testbar ist. Zweitens kann man Ressourcen
immer in einer definierten Reihenfolge allozieren.
Dirk K. schrieb:> Ich kann dir noch die Gang of Four empfehlen, das ist> das Standardwerk schlechthin:
Hab ich mir damals[tm] als es aktuell war gekauft.
Ich war zunächst von der Idee begeistert. Dann ist aber sehr schnell
Ernüchterung in der Anwendung gekommen und es blieben nur zwei Patterns
übrig (eines war Factory wimre).
Also für mich war das glatt rausgeschmissenes Geld, die Idee ist
oberflächlich gut, real aber eher heiße Luft.
Stefan F. schrieb:> Wer würde heute noch mit einem PC unter Windows 3.0> arbeiten wollen? Wohl auch kaum jemand.
Wobei Windows 3.0 dank der heutzutage extrem verstaubten Pseudo-3D-Optik
wenigstens eindeutig klarstellt, wo man für eine Aktion hinklicken kann.
Selbst Teletubby-XP konnte das wunderbar. Jetzt, wo wir auf Arbeit auf
Office365 umgestellt haben, findet man keine Buttons mehr, weil es keine
Buttons mehr gibt - nur noch Strichzeichnungen, die manchmal blau,
manchmal grau und manchmal nur der Optik wegen da sind.
> Erinnerst du dich noch an die zeit, wo man die IDE beenden musste,> um den Compiler laufen lassen zu können oder das eigene Programm> starten zu können? Ich will nicht zurück in die 90er!
Nur, weil man die 90er nicht mehr wiederhaben will, muss man ja nicht
die ganzen Erkenntnisse und funktionierenden(!) Ansätze aus den 90ern
wegschmeißen.
Btw: Um Android 10 zu bauen, brauchst du unter Linux mindestens 16 GB
RAM, sonst stürzt der Compiler mit sehr obskuren Fehlermeldungen ab -
unabhängig vom Swap. Vielleicht nicht ganz das gleiche Problemniveau wie
Windows 95, aber trotzdem spaßig, wenn man es nicht erwartet.
Was ich begrifflich nicht verstehe: mainControlLoop und RTOS sind doch
keine Gegensätze. Wo früher eine Loop mit 10 oder 100 Modulen werkelten,
+ noch Mal ebensoviele letztendlich Interruptgetriggert, ist das ganze
heute aufgeteilt in ein paar Tasks, in denen die Module je trotzdem
geloopt sind.
Der Gegensatz ist Loop vs. Eventbasiert. Nicht für Treiber (UART
natürlich eventbasiert) sondern den Prozess.
Autosar z.b. ist vorwiegend loopbasiert im Taskgewand.
Stefan F. schrieb:> Die großen anfänglichen Fortschritte der 70er bis 90er Jahre mit wenig> Aufwand wirst du im IT Bereich nicht mehr erleben.
Das kann auch Verklärung sein.
Seit den 60ern ist klar, dass SW mehr Aufwand ist als HW. Genau das sagt
der damals (!) geprägte Begriff SW-Krise aus. Auch damals arbeiteten
1000e programmierer an einer SW..
Aber so wie Steve wosz oder Allen/Gates damals alleine und ohne Geld
alle tec-firmen überflügeln konnten, geht das wie bei Zuckerberg und
musk auch in den nächsten Jahren. Heute kann jedes Kind bei Interesse
ein geniales wearable erfinden.
Andre schrieb:> Denke die Zeiten in denen noch mit einer "Main Control Loop"> versucht wurde solche Systeme zum Laufen zu bekommen, sollten lange> vorbei sein.
Warum sollte sie?
Nichts ist zuverlässiger, einfacher zu verifizieren und einfacher zu
debuggen.
Die Abarbeitungsfolge ist eindeutig bestimmt, keine Task kann der andern
Variablen unter dem Hintern wegziehen oder halb alte, halb neue liefern.
Sie läßt sich auch gut im Team entwickeln. Dazu muß jeder nur die
maximale und die durchschnittliche Zeit seiner Tasks je Iteration
angeben.
Das Problem steckt nur in den Köpfen der Programmierer. Sie müssen
lernen, wie man Wartezeiten an die Mainloop zurück gibt, statt Schleifen
zu drehen, bzw. länger dauernde Tasks in Subtasks zu zerlegen, damit die
Zeitbedingungen eingehalten werden.
Ein RTOS verleitet viel eher zu schlampiger Programmierung, weil
Verletzungen der Echtzeit viel schwerer zu analysieren sind.
Wenn ich die Wahl hätte, würde ich mir eher einen Herzschrittmacher
einsetzen lassen, dessen Firmware mit Mainloop arbeitet, als einen mit
RTOS.
A. S. schrieb:> Was ich begrifflich nicht verstehe: mainControlLoop und RTOS sind doch> keine Gegensätze.
Nein, aber schon unterschiedliche Ansätze. Salz ist auch nicht das
Gegenteil von Zucker.
Von einem RTOS erwartet man die Fähigkeit, laufende Threads zu
unterbrechen um sie später fortzusetzen, wenn dafür Zeit übrig ist. Das
kann eine Main-Loop mit FSM nicht bieten.
Oft wird beides miteinander kombiniert. Loop und/oder Event basierter
Ablauf innerhalb einer Anwendung + ein präemtives Betriebssystem, das
mehrere Anwendungen ausführt.
Es sind beliebig viele Mischformen denkbar.
A. S. schrieb:> Aber so wie Steve wosz oder Allen/Gates damals alleine und ohne Geld> alle tec-firmen überflügeln konnten, geht das wie bei Zuckerberg und> musk auch in den nächsten Jahren.
Ich wusste gar nicht, dass her Zuckerberg und Elon Musk ihre Software
alleine entwickelt haben. Wie geht das?
> Heute kann jedes Kind bei Interesse> ein geniales wearable erfinden.
Erfinden: ja, Umsetzen: nein. Oder zeige mir ein geniales Beispiel.
Stefan F. schrieb:> Von einem RTOS erwartet man die Fähigkeit, laufende Threads zu> unterbrechen um sie später fortzusetzen, wenn dafür Zeit übrig ist. Das> kann eine Main-Loop mit FSM nicht bieten.
Doch.
Wenn die einzelnen Tasks auch FSMs sind die nicht sinnlos in einer
Schleife auf irgendwas warten. Die Task kehrt zurück, wenn nichts zu tun
ist, oder wenn sie noch auf irgendwas wartet.
Ich hab das so verbessert, dass der Main-Loop mitgeteilt wird, dass die
aktuelle Task noch wartet, und dass sie daher noch X-mal übersprungen
werden kann.
Damit das alles schön funktioniert gibt es eine einzige einfache Regel:
"No blocking code".
Nick M. schrieb:> Dirk K. schrieb:>> Ich kann dir noch die Gang of Four empfehlen, das ist>> das Standardwerk schlechthin:>> Hab ich mir damals[tm] als es aktuell war gekauft.> Ich war zunächst von der Idee begeistert. Dann ist aber sehr schnell> Ernüchterung in der Anwendung gekommen und es blieben nur zwei Patterns> übrig (eines war Factory wimre).>> Also für mich war das glatt rausgeschmissenes Geld, die Idee ist> oberflächlich gut, real aber eher heiße Luft.
Viele Entwickler, die sich mit Patterns beschäftigen
sind der Meinung, diese auf Teufel-komm-raus anwenden
zu müssen. Patterns sollte man nur nach reichlicher
Überlegung verwenden, also sparsam und nur, wenn es
wirklich Sinn macht.
Es kann sein, dass du mit Entwicklung von Hardware-naher
Software weniger Fälle hast, wo man Patterns einsetzen kann.
Es kommt auch ein wenig auf die Programmiersprache an, die
man verwendet. Mit reinem C wird es da schon schwierig.
Ich entwickle Software überwiegend im Client-Server-Bereich
und ich habe sicher schon mehr als die Hälfte der Patterns
aus der Gang of Four angewendet. Wenn der Anwendungsfall
passt, dann sind Patterns unschlagbar. Aber man muss eine
Ahnung davon haben, welche es gibt, um diesen Fall zu
erkennen.
merciless
Stefan F. schrieb:> Ich wusste gar nicht, dass her Zuckerberg und Elon Musk ihre Software> alleine entwickelt haben. Wie geht das?
Musk und sein bruder haben im wesentlichen paypal erfunden und auch
selber runterprogrammiert, dann verkauft ... und nie wieder
programmiert.
so werden millionäre/visionäre geboren oder?!
keyword ist z.b. tippingpoint
also wenn revolution, innovation oder irgendeine krise uns rüttelt und
schüttelt, dann werden die helden geboren.
so im sinne von, wie phönix aus der asche ... weil, die anderen sind
dann noch paralysiert.
mt
Dirk K. schrieb:> Es kann sein, dass du mit Entwicklung von Hardware-naher> Software weniger Fälle hast, wo man Patterns einsetzen kann.
Ah, sorry, das mit den patterns war zu meiner Nicht-µC-Zeit. Das war
unter Windows.
Jetzt (mit µC) hätte ich keinerlei Verwendung mehr für das Buch.
Stefan F. schrieb:> Von einem RTOS erwartet man die Fähigkeit, laufende Threads zu> unterbrechen um sie später fortzusetzen, wenn dafür Zeit übrig ist. Das> kann eine Main-Loop mit FSM nicht bieten.
In der Praxis war das seinerzeit der Code, der im Interrupt lief.
interrupts sind quasi nichts anderes als hochpriore
prozessorimplementierte Tasks. Nur das die Interrupts als Statemaschine
implementiert werden mussten. Oder die bekannten wrapper dafür mit
#define Gräbern.
Sobald man mehrere k Speicher hat und nicht auf 1€ schauen muss, wäre es
unsin, heute kein RTOS unter die Loop(s) zu legen.
Peter D. schrieb:> Andre schrieb:>> Denke die Zeiten in denen noch mit einer "Main>> Control Loop" versucht wurde solche Systeme zum>> Laufen zu bekommen, sollten lange vorbei sein.>> Warum sollte sie?> Nichts ist zuverlässiger, einfacher zu verifizieren> und einfacher zu debuggen.>> [...]>> Das Problem steckt nur in den Köpfen der Programmierer.
Ja -- aber dort wurde es wohl auch durch den üblichen
Lehrkanon herangezüchtet.
Als Ursprung aller Dinge wird ja der Algorithmus angesehen,
also eine Vorschrift, die nach endlich vielen Schritten
terminiert (!) und das Ergebnis liefert. Vom Algorithmus
geht es dann lustig weiter zur Turing-Maschine, der
Berechenbarkeit, den Grammatiken, den formalen Sprachen
und den Programmen.
Das Problem an der Sache: Steuerungsanwendungen haben
in diesem Sinne überhaupt kein "Ergebnis"; das Halteproblem
ist völlig irrelevant. Schon der abstrakte Begriff des
Algorithmus ist nicht adäquat.
Der angemessene Ausgangspunkt für die Theorie wäre somit
folgende Frage: "Gegeben ist das Verhalten von k (endlichen)
Automaten, etwa durch Automatengraphen oder Wahrheitswerte-
tabellen. Wie lässt sich das Verhalten all dieser Automaten
so auf eine einzige sequenziellen Maschine abbilden, dass
die sequenzielle Maschine das Verhalten all dieser endlichen
Automaten gleichzeitig zeigt?"
Andre schrieb:> Meine Frage dazu ist, ob es ein Buch gibt, dass weitere Pattern im> Architekturkontext vorstellt und diese in C bzw. C++ umsetzt?
Das Wort "Architekturkontext" ist natürlich sehr weit zu fassen. Als
Student war ich auch der Versuchung verfallen, alles möglichst in
"Pattern" (d.h. Schubladen) einordnen zu können. Das Problem an der
Sache ist, dass es (in den meisten Fällen) nicht funktioniert. Ich habe
soeben mal einen Blick in die von dir genannte Literatur geworfen und
versuche das mal zu übersetzen:
> Observe and React
Ein (Sensor-)Wert wird beobachtet und bei einem bestimmten Ereignis
werden bestimmte Maßnahmen ergriffen (Prozesse gestartet). Beispiel:
Eine Alarmanlage wird durch einen Tür- oder Fensterkontakt ausgelöst,
eine Sirene heult auf und das Licht geht an.
> Environmental Control
Eine typische Regelschleife, es gibt Sensoren und Aktoren. Ein oder
mehrere Sensoren werden ausgelesen, in einem Regler verarbeitet und der
Aktor oder die Aktoren entsprechend angesteuert. Im Buch wurde als
Beispiel das ABS vom Auto genannt aber es gibt sicher unzählige andere
Beispiele, etwa Drehzahlregelung bei einem Motor, Temperaturregelung bei
einer Heizung, etc.
> Process Pipeline
Hier geht es nur darum (Sensor-)Daten zu erfassen, gegebenenfalls
weiterzuverarbeiten und sie anschließend zu verschicken.
Soweit so gut. Stellt sich mir nur die Frage, wo denn jetzt der
Unterschied zwischen "Observe and React" und "Environmental Control"
ist. Nehmen wir mal als Beispiel eine einfache Herdplatte, bei der mit
einem einfachen Einpunktsteller (also ohne Hysterese) die Temperatur
geregelt werden soll, d.h. Heizung an, solange Temperatur unter dem
Sollwert, ansonsten Heizung aus. Ist das jetzt "Observe and React" oder
"Environmental Control"? Im Beispiel mit der Alarmanlage würden laut
Sommerville bei deren auslösen ein "audible alarm process" und ein
"lightning alarm process" gestartet, während das ABS-Steuergerät eine
(wie auch immer geartete) direkte Verbindung zu den Bremsen im
Blockdiagramm dargestellt hatte. Würde man dort stattdessen einen
"delock brake process" einführen, wäre das dann unter "Observe and
React" einzuordnen? Wie man denke ich deutlich erkennen kann ist diese
Einordnung in die beiden Kategorien ziemlicher Humbug.
Andre schrieb:> Echtzeitsoftware
"Echtzeit" ist an sich schon ein sehr verwaschener Begriff. Ich
persönlich verstehe darunter, dass ein System innerhalb einer
definierten Zeit garantiert auf bestimmte Ereignisse reagieren können
muss. Wie groß jedoch diese Zeitdauer ist, kann ganz unterschiedlich
sein. Manchmal sind es Mikrosekunden, manchmal Sekunden. Bestes Beispiel
ist ja die von Sommerville erwähnte Alarmanlage, die ich durchaus auch
als "Echtzeitsystem" bezeichnen würde. Bei dieser Alarmanlage ist es
jedoch normalerweise vollkommen ok, wenn der Alarm binnen einer Sekunde
nach Auslösung startet. Reaktionszeiten im Mikrosekundenbereich sind
definitiv nicht nötig aber es sollte auch nicht zehn Minuten dauern bis
der Alarm losgeht. Eine solche Alarmanlage könnte man also locker
mittels Polling aus der Main-loop realisieren und das selbst bei einem
sehr langsam getakteten Controller. Bei einem Airbag auf der anderen
Seite, spielt es definitiv eine Rolle ob der rechtzeitig zündet oder
nicht und da hat man auch keine Zeit zu verlieren. Da braucht man dann
entweder eine main-loop die schnell genug ist oder man realisiert das
per Interrupt, was ich in dem Fall bevorzugen würde.
Wie man "Echtzeitsysteme" am besten realisiert, dass findet man meiner
Meinung nach am besten in der Praxis raus, d.h. mehr Handwerk, weniger
Architektur. Nimm dir irgendein Projekt vor und frage andere,
erfahrenere Leute wie sie dieses oder jenes lösen würden und warum. Das
einzige Buch was mir zu diesem Thema einfällt und was ich
weiterempfehlen kann, ist "Embedded Controller" von Rüdiger Asche. Das
ist zumindest relativ praxisnah.
PS:
Von Richard Barry, dem Autor von FreeRTOS gibt es noch das Buch
"Mastering the FreeRTOS Realtime-Kernel". Hilfreich zum Thema RTOS fand
ich persönlich auch die Dokumentation zu ChibiOS. Mit dem Thema RTOS
würde ich mich aber erst beschäftigen wenn die anderen handwerklichen
Grundlagen sitzen.
Nick M. schrieb:>> Von einem RTOS erwartet man die Fähigkeit, laufende Threads zu>> unterbrechen> Wenn die einzelnen Tasks auch FSMs sind die nicht sinnlos in einer> Schleife auf irgendwas warten.
Du beschreibst kooperatives Multitasking. Die alten Hasen kennen das
nicht nur von der FSM auf Mikrocontrollern, sondern auch von Event
basierten Systemen wie Windows bis Version 3.11 sowie Android bis
Version 3.
(Neuere versionen bieten zusätzlich das präemptive Multitaksing)
Wie gesagt erwartet man von einem RTOS, dass es aktiv, präemptiv
unterbrechen kann. Sonst ist es kein RTOS.
Stefan F. schrieb:> Nick M. schrieb:>>> Von einem RTOS erwartet man die Fähigkeit,>>> laufende Threads zu unterbrechen>>> Wenn die einzelnen Tasks auch FSMs sind die>> nicht sinnlos in einer Schleife auf irgendwas>> warten.>> Du beschreibst kooperatives Multitasking.
Nein. Falsch.
Er beschreibt STEUERUNGSPROGRAMMIERUNG.
Wenn man über geeignete Werkzeuge absichert, dass
KEINE LOKALEN SCHLEIFEN formuliert werden können
(was der Turing-Vollständigkeit keinen Abbruch tut),
dann ist dadurch Blockierungsfreiheit GARANTIERT (!).
> Wie gesagt erwartet man von einem RTOS, dass es> aktiv, präemptiv unterbrechen kann. Sonst ist es> kein RTOS.
Auch falsch: Nicht "man" erwartet das, sondern "der
klassisch für interaktive Software geschulte
Informatiker" erwartet das.
Man KANN Programme auch ganz anders strukturieren als
nach den Regeln der strukturierten oder objektorientierten
Programmierung -- aber das kommt für "echte Informatiker"
unter überhaupt keinen Umständen in Frage. Das ist etwas
für verblödete Elektriker...
Komischerweise wird über SQL nicht so gedacht...
Marten Morten schrieb:> Making Embedded Systems: Design Patterns for Great Software> https://www.amazon.com/Making-Embedded-Systems-Patterns-Software/dp/1449302149/
Ich habe es vor ein paar Jahren mal gelesen und war sehr enttäuscht. Im
Großen und Ganzen eine Ansammlung von Selbstverständlichkeiten, die
selbst jemanden mit reiner Arduino-Erfahrung nicht vom Hocker hauen.
Wer Unterstützung auf dem Weg einfache Mikrocontrollerprogramme ->
komplexere Mikrocontrollerprogramme sucht, findet keinen Nutzen.
Vielleicht ist die Zielgruppe PC-Programmierer, die mit Embedded
anfangen, und im Vorstellungsgespräch nicht zu unwissend herüberkommen
wollen.
Egon D. schrieb:> Man KANN Programme auch ganz anders strukturieren
Ja, kann man, dann steckt aber nichts dahinter, was den Namen RTOS
trägt.
Ich habe nicht gesagt, dass RTOS der Weisheit letzter Schluss ist. Ich
bin allerdings dagegen, einen fleischlosen Salat im Fladenbrot Döner zu
nennen.
Stefan F. schrieb:> Ich wusste gar nicht, dass her Zuckerberg und Elon Musk> ihre Software alleine entwickelt haben. Wie geht das?
Paypal wurde bereits genannt. Ich werfe mal ein anderes Beispiel in den
Raum: Minecraft war auch im wesentlichen eine lukrative Ein-Mann-Show,
bis es dann für viel Geld von Microsoft gekauft wurde.
Stefan F. schrieb:> Egon D. schrieb:>> Man KANN Programme auch ganz anders strukturieren>> Ja, kann man, dann steckt aber nichts dahinter, was> den Namen RTOS trägt.
Mag sein.
Das bestärkt mich allerdings nur in meiner Meinung,
dass Informatiker unfähig zur Wahl sinnvoller
Bezeichnungen sind.
Für mich ist die Firmware, die auf einer klassischen
SPS läuft, sehr wohl ein Echtzeit-Betriebssystem,
denn diese Firmware nimmt Aufgaben eines Betriebs-
systems wahr, und echtzeitfähig ist eine SPS auch.
Multitasking ist dafür nicht erforderlich -- also
sehe ich keinen sinnvollen Grund, warum ich das zum
k.o.-Kriterium machen sollte.
Aber meine Meinung zählt nicht, denn ich bin kein
Informatiker. Gott sei Dank. :)
Egon D. schrieb:> Für mich ist die Firmware, die auf einer klassischen> SPS läuft, sehr wohl ein Echtzeit-Betriebssystem,
Das hat doch niemand abgestritten!
Es geht um den Begriff RTOS.
RTOS steht für Betriebssysteme, die präemptives Multitasking anwenden.
Niemand sagt, dass RTOS das einzige Multitasking fähige System sei.
Niemand sagt, dass an RTOS kein Vorbei führt.
Ich schon gar nicht, ich empfehle hier immer wieder Zustandsautomaten
und den Verzicht auf Warteschleifen.
Stefan F. schrieb:> Egon D. schrieb:>> Für mich ist die Firmware, die auf einer klassischen>> SPS läuft, sehr wohl ein Echtzeit-Betriebssystem,>> Das hat doch niemand abgestritten!>> Es geht um den Begriff RTOS.
???
"RTOS" steht in meinem Universum für "Real Time
Operating System", übersetzt "Echtzeit-Betriebssystem".
Wieso ist die Firmware einer SPS zwar ein Echtzeit-
Betriebssystem, aber kein RTOS?
Jetzt sage aber BITTE nicht "Weil sie nicht
multitaskingfähig ist". Ich suche einen sachlichen,
technischen Grund -- keine willkürliche, sinnfreie
Festlegung.
> RTOS steht für Betriebssysteme, die präemptives> Multitasking anwenden.
Wenn das tatsächlich so ist, dann ist das -- wie oben
schon gesagt -- eine absolut sinnfreie Festlegung.
Wenn weder für die Echtzeitfähigkeit noch für die
Entkopplung der einzelnen Aufgaben "Tasks" notwendig
sind, braucht das System auch kein Multitasking, und
wenn das System kein Multitasking braucht, braucht es
erst recht kein präemptives Multitasking.
Trotzdem kann es ein Echtzeit-Betriebssystem sein, also
auf Englisch ein "real time operation system" -- RTOS.
> Niemand sagt, dass RTOS das einzige Multitasking> fähige System sei.> Niemand sagt, dass an RTOS kein Vorbei führt.>> Ich schon gar nicht, ich empfehle hier immer wieder> Zustandsautomaten und den Verzicht auf Warteschleifen.
Der Teil ist klar und unstrittig.
Egon D. schrieb:> Wieso ist die Firmware einer SPS zwar ein Echtzeit- Betriebssystem, aber> kein RTOS?
Es ist jedem Begriff immanent, dass wir geringfügig verschiedene
Auffassungen davon haben.
Für viele fängt RTOS halt erst bei präemptiv an. Weil es darunter
"einfach", "normal" ist. Dass eine sps vermutlich genügend präemptives
unter der Haube hat, wovon die Loop nichts mitbekommt (stört sie ja
nicht, wenn sie x us pausiert), geschenkt. Das vielen was kooperatives
schon ausreicht, auch. Und bei anderen ist autosar mit basic-tasks schon
ein RTOS, wo es nicht Mal sleep oder Task-Wechsel gibt.
Egon D. schrieb:> "RTOS" steht in meinem Universum für "Real Time> Operating System", übersetzt "Echtzeit-Betriebssystem".
Da liegst du genau so falsch, als ob jemand sagen würde "Linux und Mac
OS sind Windows Systeme weil sie Fenster haben".
RTOS bedeutet wesentlich mehr, als die reine Ausschreibung der
Abkürzung.
Siehe freertos.org, CMSIS-RTOS, RTOS-32
A. S. schrieb:> Egon D. schrieb:>> Wieso ist die Firmware einer SPS zwar ein Echtzeit->> Betriebssystem, aber kein RTOS?>> Es ist jedem Begriff immanent, dass wir geringfügig> verschiedene Auffassungen davon haben.
Mit GERINGFÜGIG differierenden Auffassungen habe ich
kein Problem. Es gibt immer Grenzfälle, die nicht
ganz eindeutig zuzuordnen sind.
Es ist auch nicht ganz zu vermeiden, dass bestimmte
eigentlich allgemeine Begriffen in einem konkreten
Kontext eine deutlich engere Bedeutung annehmen --
aber dafür sollte es dann schon einen guten Grund
geben. Den kann ich bei RTOS nicht erkennen.
Multitaskingfähigkeit ist nämlich weder für Betriebs-
systeme allgemein eine notwendige Bedingung noch für
Echtzeitsysteme.
> Für viele fängt RTOS halt erst bei präemptiv an.
Das hatte ich Stefans Insistieren schon entnommen.
Meine Frage ist: Warum?
Meine Unterstellung dazu ist: Der Durchschnitts-
informatiker kann sich schlicht nicht vorstellen,
dass mehrere unabhängige Teilaufgaben in Echtzeit
zu bewältigen sind, OHNE auf klassische "Tasks"
zurückzugreifen. Es überschreitet einfach seinen
Horizont.
Er überträgt die Begriffe und Systemstrukturen,
die er von interaktiv genutzten Multi-User-Systemen
kennt, auf Echtzeitsteuerungen und schnauft dann
verächtlich durch die Nase, weil die Welt der
Echtzeitsteuerungen so schrecklich "veraltet" und
"rückständig" ist.
Dass der dort gewählte Ansatz theoretisch genauso
fundiert ist wie sein gewohnter Multi-Tasking-Krempel,
das interessiert ihn nicht.
> Weil es darunter "einfach", "normal" ist.
"Darunter" setzt aber eine lineare Ordnung, d.h.
Eindimensionalität voraus, die so nicht existiert.
Ein SPS-Betriebssystem würde ich technisch
keinesfalls mit MS-DOS auf eine Stufe stellen.
> Dass eine sps vermutlich genügend präemptives> unter der Haube hat, wovon die Loop nichts> mitbekommt (stört sie ja nicht, wenn sie x us> pausiert), geschenkt.
Ja, das ist ein anderes Thema.
Es bleibt aber festzuhalten, dass eine klassische
SPS im echtzeitfähigen Userspace keine "Tasks"
kennt -- und diese auch nicht braucht.
> Das vielen was kooperatives schon ausreicht, auch.
Naja, was heißt "kooperativ"?
Ich möchte hier wahrlich keine Lanze für AWL brechen,
aber ich wüsste andererseits auch keinen Grund, warum
man das "Steuerungsparadigma" (=Hauptschleife) nicht
mit Rechteverwaltung, Zugriffsschutz etc. anreichern
können sollte.
Wenn der Compiler nur konforme Module übersetzt und
das... ähh... Echtzeitbetriebssystem nur konforme
Module läd und ausführt, KANN es keine Blockierungen
geben. Man BRAUCHT also weder Tasks noch präemptives
Multitasking.
Der einzige Hinderungsgrund ist: Übliche strukturierte
Sprachen unterstützen diese Vorgehensweise nicht.
Egon D. schrieb:> Meine Unterstellung dazu ist: Der Durchschnitts-> informatiker kann sich schlicht nicht vorstellen,> dass mehrere unabhängige Teilaufgaben in Echtzeit> zu bewältigen sind, OHNE auf klassische "Tasks"> zurückzugreifen. Es überschreitet einfach seinen> Horizont.>> Er überträgt die Begriffe und Systemstrukturen,> die er von interaktiv genutzten Multi-User-Systemen> kennt, auf Echtzeitsteuerungen und schnauft dann> verächtlich durch die Nase, weil die Welt der> Echtzeitsteuerungen so schrecklich "veraltet" und> "rückständig" ist.
Was ist denn das für eine Unterstellung? Sind alle doof, nur du nicht?
Walter T. schrieb:> Marten Morten schrieb:>> Making Embedded Systems: Design Patterns for Great Software>> https://www.amazon.com/Making-Embedded-Systems-Patterns-Software/dp/1449302149/>> Ich habe es vor ein paar Jahren mal gelesen und war sehr enttäuscht. Im> Großen und Ganzen eine Ansammlung von Selbstverständlichkeiten, die> selbst jemanden mit reiner Arduino-Erfahrung nicht vom Hocker hauen.
Volle Zustimmung, war rausgeworfenes Geld.
Egon D. schrieb:>> RTOS steht für Betriebssysteme, die präemptives>> Multitasking anwenden.
RTOS sind für mich Multitasking-Systeme, die einen Echtzeitbetrieb
ermöglichen, um als Teil einer Firmware zu laufen. Präemptives
Multitasking ist dafür nicht erforderlich. In manchen Situationen wird
man es sogar vermeiden wollen. Ein wesentlicher Unterschied zu
"klassischen" Betriebssystemen wie Linux ist, dass sie keine Programme
starten, sondern viel mehr als Teil eines Programms laufen, das "bare
metal" auf einem Embeded-System läuft. FreeRTOS ist für mich ein
typisches RTOS, bei dem man übrigens konfigurieren kann, ob das
Multitasking präemptiv arbeiten soll.
> Wenn das tatsächlich so ist, dann ist das -- wie oben> schon gesagt -- eine absolut sinnfreie Festlegung.
Ob willkürlich oder nicht, es ist eine Festlegung. "Automobil" heißt
auch erstmal sowas wie "sich aus eigenem Antrieb fortbewegend". Das tut
ein Eisenbahnzug oder ein Schiff auch. Trotzdem bezeichnet man sie nicht
als "Automobile".
Egon D. schrieb:>> Das vielen was kooperatives schon ausreicht, auch.>> Naja, was heißt "kooperativ"?
Das heißt, dass der Scheduler die Tasks nicht zu mehr oder weniger
beliebigen Zeiten unterbricht, sondern nur, wenn diese sich explizit
schlafen legen oder auf irgendwas warten. Die Tasks müssen kooperieren,
damit alle dran kommen können.
Egon D. schrieb:> Ich möchte hier wahrlich keine Lanze für AWL brechen,> aber ich wüsste andererseits auch keinen Grund, warum> man das "Steuerungsparadigma" (=Hauptschleife) nicht> mit Rechteverwaltung, Zugriffsschutz etc. anreichern> können sollte.
Der zentrale Punkt eines RTOS sind für mich nicht Zugriffsrechte,
sondern das Scheduling.
Stefan F. schrieb:> RTOS steht für Betriebssysteme,> die präemptives Multitasking anwenden.
Wie kommst du denn auf das schmale Brett?
Echtzeitsysteme sind Systeme, die Zeitgarantien abgeben können. Ob das
nun mit präemptivem Multitasking passiert oder auf eine andere Weise,
ist doch egal. Auch kooperative Betriebssysteme können solche Garantien
abgeben.
Übliche Multimedia-Betriebssysteme können das im Allgemeinen nicht, und
zwar auch dann nicht, wenn sie präemptives Multitasking verwenden.
Es gibt übrigens kein universales Mittel gegen Blockierung :
Der eine Programmteil hat eine Ressource, auf welche ein anderer wartet,
während welcher auf eine Ressource wartet, die dieser hat.
Zu Preemptive und Kooperativ. Kooperativ ist genuegend falls alle
Teilschritte ueberall in der Gegend von gleich lang sind, und dieses
gleichlang trotzdem einiges kuerzer wie die Reaktionszeit ist.
Programmteile welche erwartbar laenger wie die Reaktionszeit sind
muessen unterbrechbar sein.
Das Breitschwert dazu : Preemptive MT : alles ist jederzeit
unterbrechbar.
Joggel E. schrieb:> Es gibt übrigens kein universales Mittel gegen Blockierung :> Der eine Programmteil hat eine Ressource, auf welche ein anderer wartet,> während welcher auf eine Ressource wartet, die dieser hat.
Das wäre ein klassischer Deadlock. Eine Möglichkeit, den zu vermeiden,
ist, indem man die erste Ressource acquiriert, dann versucht, die zweite
zu acquirieren, ohne zu blockieren (Bei Pthreads z.B. mit
pthread_mutex_trylock), und wenn das fehlschlägt, die erste Ressource
wieder freigibt und es nochmal von vorne probiert.
> Zu Preemptive und Kooperativ. Kooperativ ist genuegend falls alle> Teilschritte ueberall in der Gegend von gleich lang sind, und dieses> gleichlang trotzdem einiges kuerzer wie die Reaktionszeit ist.>> Programmteile welche erwartbar laenger wie die Reaktionszeit sind> muessen unterbrechbar sein.
Dazu müssen sie nicht unbedingt präemptiv sein. Es gibt beispielsweise
oft eine yield-Funktion, mit der ein Programmteil explizit den Prozessor
für andere freigeben kann. Wenn man eine lange Schleife hat, kann man
z.B. bei jedem 1000. Durchlauf ein yield machen, damit auch andere
inzwischen drankommen.
Die Abkürzung RTOS sagt nichts über die Art des Multitasking aus.
Der TO fragte nach state of the Art Implementierungen. Ich nannte ihm
die Control Loop als immer noch aktuelles Beispiel für kooperatives
Multitasking und im Kontrast dazu RTOS als aktuelles Beispiel für
präemtives Multitasking.
Dabei hatte ich aktuelle RTOS Varianten im Sinn, die ich später auch
namentlich nannte. Alle aktuellen RTOS implementierungen können präemtiv
wechseln.
Die Sache ist, als ob jemand nach modernen Fortbewegungsmitteln für
Familien fragt und dann wird das Auto als falsche Antwort entlarvt, weil
es Autos für nur zwei Personen gibt.
Um diesen Shitstorm zu beenden: RTOS ist die Abkürzung von Real Time
Operating System. Alle (wirklich?) aktuellen Betriebssysteme mit RTOS im
Namen können präemtiv multi-tasken. Das ist aber nicht der Grund für den
Namen RTOS.
Joggel E. schrieb:> Es gibt übrigens kein universales Mittel gegen Blockierung :> Der eine Programmteil hat eine Ressource, auf welche ein anderer wartet,> während welcher auf eine Ressource wartet, die dieser hat.
Das ist ein Problem der RTOS-Verwender!
Mit FSMs kein Problem. Die kommunizieren über Messages die in
Warteschlangen eingetragen werden. Und die jeweilige Resource wird nur
von einer einzigen FSM bedient. Und die arbeitet die Nachrichten einfach
in der Reihenfolge ab. Kein Deadlock.
Rolf M. schrieb:> Joggel E. schrieb:>> Es gibt übrigens kein universales Mittel gegen Blockierung :>> Der eine Programmteil hat eine Ressource, auf welche ein anderer wartet,>> während welcher auf eine Ressource wartet, die dieser hat.>> Das wäre ein klassischer Deadlock. Eine Möglichkeit, den zu vermeiden,> ist, indem man die erste Ressource acquiriert, dann versucht, die zweite> zu acquirieren, ohne zu blockieren (Bei Pthreads z.B. mit> pthread_mutex_trylock), und wenn das fehlschlägt, die erste Ressource> wieder freigibt und es nochmal von vorne probiert.
Eine andere Möglichkeit ist die Realisierung von "priority inheritance".
Der niedriger priorisierte Thread wird auf die Priorität jenes Threads
befördert, der auf ihn wartet.
Christopher J. schrieb:> Eine andere Möglichkeit ist die Realisierung von "priority inheritance".> Der niedriger priorisierte Thread wird auf die Priorität jenes Threads> befördert, der auf ihn wartet.
Richtig. Nur hat man dann andere Probleme. Das schöne an der Loop ist
dagegen, dass es vergleichbare Probleme nicht gibt. Es kommen halt immer
alle dran.
A. S. schrieb:> Das schöne an der Loop ist> dagegen, dass es vergleichbare Probleme nicht gibt. Es kommen halt immer> alle dran.
Und der Task der auf eine Nachricht wartet, sagt das dem "Taskmanager"
und legt sich schlafen. Sobald eine Nachricht für ihn da ist, wird er
aufgeweckt und bekommt die Nachricht.
Nick M. schrieb:> Und der Task der auf eine Nachricht wartet, sagt das dem "Taskmanager"> und legt sich schlafen. Sobald eine Nachricht für ihn da ist, wird er> aufgeweckt und bekommt die Nachricht.
Ja. Das ist der Ansatz, der bei Client/Server und bei kognitivem
Benutzer sinnvoll ist. Oder bei Treibern, z.b. serielle. Die Loop führt
bei Steuerungstechnik.
Christopher J. schrieb:> Eine andere Möglichkeit ist die Realisierung von "priority inheritance".> Der niedriger priorisierte Thread wird auf die Priorität jenes Threads> befördert, der auf ihn wartet.
Das bringt dir aber für den genannten Deadlock nichts.
Das Problem mit Main-Loops ist, das sie zwar für überschaubare Probleme
schnell zu Ergebnissen führen, aber bei großen Projekten zu
Write-Once-Code führen, der kaum wartbar ist.
Die Ursache ist, das jede noch so kleine Sequenz von Aktionen, in eine
FSM gepresst werden muss. Aber die Sprachmittel der gängigen
Programmiersprachen (und auch SPSen) sind dafür miserabel geeignet.
Praktisch immer landet man bei einer switch/case-Konstruktion mit einer
händisch gepflegten Liste von numerischen Zuständen.
Änderungen an diesen FSM-Implementationen sind sehr fehleranfällig da
die Logik undurchsichtig über viele Case-Blöcke verteilt ist. Außerdem
wird oft wild hin und her gesprungen.
Im Prinzip sind diese FSM in switch/case-Ausführung nichts anderes als
Spaghetti-Code mit Zeilennummern und Goto-Anweisungen. Es gibt darin
keinerlei strukturierte Programmanweisungen (for/while/if/else etc.).
Die Folgen von Goto-Anweisungen (in FSM als switch/case-Struktur
vorhanden) hat Edsger W. Dijkstra im Jahre 1968 analysiert. Die
Auseinandersetzung mit diesem Thema die letzten 50 Jahre führte zu einer
gefestigten und anerkannten Lehrmeinung, die allgemein als bekannt
vorauszusetzen ist.
Von daher ist es nicht zielführend für wartbaren Code, an Main-Loops und
ähnlichen Konstrukten festzuhalten.
Suchender schrieb:> aber bei großen Projekten zu> Write-Once-Code führen, der kaum wartbar ist.
Eben nicht. Jeder in sich abgeschlossene Thread kann 1:1 in andere
Projekte kopiert werden.
Die Kommunikation zwischen Threads ist ein Thema, über das man
nachdenken sollte. Weniger gut wäre, wenn ein Thread einfach den Status
eines anderen Threads direkt manipuliert. Warteschlangen mit Ereignissen
finde ich hilfreich.
> Praktisch immer landet man bei einer switch/case-Konstruktion mit einer> händisch gepflegten Liste von numerischen Zuständen.
Kennst du keine Enumerations? Never ever würde ich numerische Zustände
benutzen. Wenn man da ein paar Zustände einfügen muss, macht man mit
hoher Wahrscheinlichkeit Fehler.
> Änderungen an diesen FSM-Implementationen sind sehr fehleranfällig da> die Logik undurchsichtig über viele Case-Blöcke verteilt ist. Außerdem> wird oft wild hin und her gesprungen.
Deswegen ist hier Dokumentation wichtig. Kommentare im Quelltext reichen
ab einer gewissen Größe nicht mehr.
Ich programmiere in Job Zustandsautomaten in größerem Stil - in Java.
Trotz Multithreading fähigem Unterbau muss ich das tun, weil diese
Prozesse Neustarts und Handover auf andere Nodes überleben müssen. Wenn
du Prozesse hast, die Stunden bis Tage laufen, kommst du um
Zustandsautomaten nicht mehr herum.
> Im Prinzip sind diese FSM in switch/case-Ausführung nichts anderes als> Spaghetti-Code mit Zeilennummern und Goto-Anweisungen. Es gibt darin> keinerlei strukturierte Programmanweisungen (for/while/if/else etc.).
Ich bin durchaus imstande, innerhalb eines switch cases von if-then-else
Gebrauch zu machen. Was ist daran für Dich so schwer?
Unabhängig davon finde ich es sehr abwegig, eine Abhandlung über GOTO
als Bestätigung zu verwenden, dass FSM schlecht seien. Dieser Mann
(Edsger W. Dijkstra) hat mehrere Aufsätze geschrieben, die den Nutzen
von FSM erklären und wie man sie gut implementiert!
> Von daher ist es nicht zielführend für wartbaren Code, an Main-Loops und> ähnlichen Konstrukten festzuhalten.
Zu pauschalisiert formuliert. Während präemptives Multitasking eine
feine Sache ist, gibt es weiterhin genug sinnvolle Anwendungsfälle für
FSM. Nicht nur auf Mikrocontrollern.
Suchender schrieb:> Das Problem mit Main-Loops ist, das sie zwar für überschaubare Probleme> schnell zu Ergebnissen führen, aber bei großen Projekten zu> Write-Once-Code führen, der kaum wartbar ist.
Nein, absolut nicht.
Meine main-loop ist super simpel. Die kennt gefühlt nur 5 Zustände.
Booten, Konfiguration laden und die anderen FSMs initialisieren,
Fehlercodes abfangen und reagieren (kaputte Konfiguration), eigentlicher
Programmlauf und wenn es aus irgendeinen Grund gewünscht wird, alles
FSMs runterfahren und neu starten.
Der eigentliche Code sind ca. 20 FSMs + nochmal ... hmmm ... 10 für
System-tasks (Ethernet, Serielle, I2C, ...). Die werden in der main-loop
aufgerufen.
Ich kann einfach eine FSM rausnehmen, ohne dass alles zusammenbricht
(solang die nicht benutzt wird da nicht so konfiguriert).
Das Ganze ist ein wunderbahrer Baukasten den man wie in der
Telefonvermittlung zusammenstöpselt (im positiven Sinne). Das
Zusammenstöpseln wird über die Konfiguration gemacht.
Die Tasks kommunizieren über Nachrichten (bis auf ganz wenige
Ausnahmen). Und die Nachrichten landen in Queues. Selbst wenn ein Task
hängenbleibt, der Rest läuft weiter.
Und wenn ein Task (Ethernet) die Daten nicht mehr wegschicken kann (wg.
Verbindung über GSM), merkt das ein Task der davor hängt und schreibt
alles auf eine SD card. Und wenn es wieder eine Verbindung gibt, werden
gleichzeitig alte Werte aus der SD card geschickt, neue Werte ermittelt
und hinten auf die SD card gschrieben oder -bei dringenden Nachrichten-
kann für die die SD-Queue übersprungen werden. Das können auch mal GB
werden, so läuft das Gerät ein Monat völlig autark.
Das geht wirklich wunderbar. Bei Änderungen ist oft nur eine FSM
betroffen.
Und dass es enums gibt für die man sprechende Namen findet (XXGetFirst,
XXLoop, XXClose, ...) sollte sich inzwischen rumgesprochen haben.
Suchender schrieb:> Die Ursache ist, das jede noch so kleine Sequenz von Aktionen, in eine> FSM gepresst werden muss. Aber die Sprachmittel der gängigen> Programmiersprachen (und auch SPSen) sind dafür miserabel geeignet.> Praktisch immer landet man bei einer switch/case-Konstruktion mit einer> händisch gepflegten Liste von numerischen Zuständen.
Du hast ja recht. Doch sobald es um Steuerungstechnik geht, ist das
Problem der Tasks, dass Du die am Ende notwendigen Events (Abbruch,
Timeout, Notaus, Fehler, …) in jeden State mit einpflegen musst. Die
Switch/Case der Loop ist nur der eine Teil, der andere ist der in jeder
Loop ausgeführte Allgemeinteil vorher und nachher.
Suchender schrieb:> Die Folgen von Goto-Anweisungen (in FSM als switch/case-Struktur> vorhanden) hat Edsger W. Dijkstra im Jahre 1968 analysiert. Die> Auseinandersetzung mit diesem Thema die letzten 50 Jahre führte zu einer> gefestigten und anerkannten Lehrmeinung, die allgemein als bekannt> vorauszusetzen ist.
Nein. Nach der Definition wäre jedes for oder while ebenso ein
Goto-Ersatz. Ob Du die States als Switch-Case, als Funktionspointer, als
Klassen oder was auch immer implementierst, am Ende must Du irgendwo von
State A zu State B Springen, und da sind enums genauso gut wie
irgendwelche andere Token. Der praktisch einzige (ärgerliche) Overhead
sind die "unnötigen" States für jedes wait. Aber (wie oben beschrieben)
brauchst Du in Steuerungstechnik auch in Tasks einen Workaround.
Suchender schrieb:> Das Problem mit Main-Loops ist, das sie zwar für> überschaubare Probleme schnell zu Ergebnissen> führen, aber bei großen Projekten zu> Write-Once-Code führen, der kaum wartbar ist.
Geht eine Rundtischmaschine mit 16 Stationen,
mehreren dutzend Sensoren und ebensovielen Aktoren
für Dich schon als "größeres Projekt" durch?
> Die Ursache ist, das jede noch so kleine Sequenz> von Aktionen, in eine FSM gepresst werden muss.
Sachlich richtig -- aber sprichst Du bei üblichen
Programmen der Gerechtigkeit halber auch davon, dass
jede Form von Eingangs-Ausgangs-Zuordnung "in ein
sequenzielles Programm gepresst" werden muss? Denn
genau das passiert.
> Aber die Sprachmittel der gängigen Programmiersprachen> (und auch SPSen) sind dafür miserabel geeignet.
Das stimmt.
> Praktisch immer landet man bei einer switch/case-> Konstruktion mit einer händisch gepflegten Liste> von numerischen Zuständen.
Richtig -- aber das ist ja eine Wechselwirkung.
Solange klassische Steuerungsprogrammierung als
Hilfsarbeit für debile Elektriker angesehen wird,
wird das kaum auf dem Radar fähiger Leute auftauchen,
die entsprechende Programmiersprachen schaffen
könnten.
Das Steuerungsprogramm für die oben erwähnte
Rundtischmaschine erstellt übrigens ein Ingenieur.
> Änderungen an diesen FSM-Implementationen sind sehr> fehleranfällig da die Logik undurchsichtig über> viele Case-Blöcke verteilt ist. Außerdem wird oft> wild hin und her gesprungen.
Wer wild hin- und herspringt, hat das Prinzip nicht
verstanden: In einer FSM gibt es nur genau EINE
Sprungrichtung -- und das ist vorwärts, also in
Richtung "Ende". Rücksprünge sind tabu!
Zustände werden in Zustandsvariablen gespeichert.
> Im Prinzip sind diese FSM in switch/case-Ausführung> nichts anderes als Spaghetti-Code mit Zeilennummern> und Goto-Anweisungen.
Das ist falsch.
> Es gibt darin keinerlei strukturierte Programmanweisungen> (for/while/if/else etc.).
Das ist auch falsch.
Schleifen sind verkappte Rücksprünge und daher natürlich
verboten; if/else und switch/case kann aber hemmungslos
verwendet werden. Diese Fallunterscheidungen folgen
durchaus den Regeln der strukturierten Programmierung.
> Die Folgen von Goto-Anweisungen (in FSM als switch/case-> Struktur vorhanden) hat Edsger W. Dijkstra im Jahre 1968> analysiert. Die Auseinandersetzung mit diesem Thema die> letzten 50 Jahre führte zu einer gefestigten und> anerkannten Lehrmeinung, die allgemein als bekannt> vorauszusetzen ist.
Der Verzicht auf alle Schleifen (bis auf eine -- die
Hauptschleife) widerspricht der strukturierten
Programmierung nicht, denn es ist eine ZUSÄTZLICHE
Einschränkung.
> Von daher ist es nicht zielführend für wartbaren Code,> an Main-Loops und ähnlichen Konstrukten festzuhalten.
Im Gegenteil.
Es wäre sinnvoll, dafür geeignete Sprachkonstrukte zu
haben.
Suchender schrieb:> Aber die Sprachmittel der gängigen Programmiersprachen> (und auch SPSen) sind dafür miserabel geeignet.
Das ist korrekt.
> Praktisch immer landet man bei einer switch/case-Konstruktion> mit einer händisch gepflegten Liste von numerischen Zuständen.
Und das ist nicht mehr korrekt.
Es hindert dich niemand daran, die FSM in einer Metasprache zu
erstellen, aus der dann eine numerische, automatisch generierte Liste
von Zuständen entsteht. Dem Compiler ist das egal, der kann mit Zahlen
besser umgehen.
In der Hardwareentwicklung - wo die FSM das Mittel der Wahl ist - ist
das ein übliches Vorgehen.
Suchender schrieb:> Die Folgen von Goto-Anweisungen (in FSM als switch/case-Struktur> vorhanden) hat Edsger W. Dijkstra im Jahre 1968 analysiert.
Erstmal hast du seinen Namen falsch geschrieben, zweitens hat er über
GOTO lamentiert und nicht über switch/case, und drittens hat die
Veröffentlichung nichts mit dem Thema zu tun.
Troll woanders.
S. R. schrieb:> Es hindert dich niemand daran, die FSM in einer Metasprache zu> erstellen, aus der dann eine numerische, automatisch generierte Liste> von Zuständen entsteht.
Zum Beispiel die Protothreads von Adam Dunkels.
Stefan F. schrieb:> Protothreads
Auch nur eine Kapselung/Abstraktion um die switch-case oder goto Methode
ins Unsichtbare zu drängen.
Technisch identisch, aber ja, evtl. etwas übersichtlicher.
Egon D. schrieb:> Schleifen sind verkappte Rücksprünge und daher natürlich> verboten;
Was für ein Käse! Wenn ich eine Schleife brauche um über irgendwas zu
iterieren verwende ich natürlich eine Schleife. Es ist bei so einem
Konzept lediglich verboten blockierend auf etwas zu WARTEN!
Arduino Fanboy D. schrieb:> Technisch identisch, aber ja, evtl. etwas übersichtlicher.
Ja eventuell. Mir gefällt es nicht, aber ich erkenne die Absicht hinter
dem Konstrukt.
Arduino Fanboy D. schrieb:> Technisch identisch, aber ja, evtl. etwas übersichtlicher.
Die Dunklen Threads sind Threads ohne RTOS. Sie bieten nicht die
Vorteile der Loop. Sie sind maximal ein Muster um dabei wait/sleep zu
realisieren.
A. S. schrieb:> Die Dunklen Threads ... bieten nicht die Vorteile der Loop.> Sie sind maximal ein Muster um dabei wait/sleep zu realisieren.
Ich glaube, du hast da etwas missverstanden. Protothreads werden aus
einer Hauptschleife heraus aufgerufen. Mit wait/sleep haben sie ziemlich
wenig zu tun.
Ich habe dort mal versucht, die Protothreads auf deutsch zu erklären:
http://stefanfrings.de/net_io/protosockets.html
A. S. schrieb:> Die Dunklen Threads sind Threads ohne RTOS. Sie bieten nicht die> Vorteile der Loop.
Sie sind sogar eine recht clevere Lösung und einem RTOS sehr nahe, ohne
dessen riesigen Ressourcenverbrauch und deren großen Problemen bei der
Messageübergabe.
Ich hab aber auch erstmal lange gebraucht, sie zu verstehen.
Peter D. schrieb:> Ich hab aber auch erstmal lange gebraucht, sie zu verstehen.
Dito. Vor allem dauerte es recht lange, bis mir klar war, wie man
Variablen innerhalb der Threads benutzen kann. Diese Art der
Verschleierung ist nicht mein Ding, ich habe das nur in einem einzigen
Projekt benutzt. Lieber switch-case, dann sieht man, was passiert.
Rolf M. schrieb:> Das bringt dir aber für den genannten Deadlock nichts.
Vielleicht hab ich es auch falsch verstanden aber hier mal meine
Auffassung des Problems:
Task A hat höchste Priorität und wartet auf Task C
Task B hat mittlere Priorität und wartet auf A
Task C hat niedrigste Priorität
Das wäre jetzt normalerweise ein Deadlock. Durch priority inheritance
bekommt aber jetzt C die Priorität von A vererbt (weil ja A auf C
wartet), wodurch zunächst C laufen kann und danach dann A und
anschließend B.
Stefan F. schrieb:> Ich glaube, du hast da etwas missverstanden. Protothreads werden aus> einer Hauptschleife heraus aufgerufen
Genau und wie Du, Peter und ich schrieben, sind sie dazu da, um wie mit
Threads zu arbeiten. Also eher ungeeignet, wenn man ein RTOS hat und
trotzdem lieber Loop will. Dass sie aus einer Loop heraus aufgerufen
werden, ist Implementierung, aber (abgesehen von Ressourcen etc) kein
Vorteil gegenüber anderen Task-schedulern.
>> Ich glaube, du hast da etwas missverstanden. Protothreads werden aus>> einer Hauptschleife heraus aufgerufenA. S. schrieb:> Genau und wie Du, Peter und ich schrieben, sind sie dazu da, um wie mit> Threads zu arbeiten. Also eher ungeeignet, wenn man ein RTOS hat und> trotzdem lieber Loop will. Dass sie aus einer Loop heraus aufgerufen> werden, ist Implementierung, aber (abgesehen von Ressourcen etc) kein> Vorteil gegenüber anderen Task-schedulern.
So war das gemeint, ergibt Sinn. Dann hatte ich dich also
missverstanden.
Christopher J. schrieb:> wodurch zunächst C laufen kann und danach dann A und anschließend B.
Ja. B muss nichtmal warten es reicht, wenn B einfach nur läuft. Aber
unter Umständen läuft C nun 1000ms, weil, ist ja Low Priorität und egal.
Zudem ist das nur ein deadlock. Der klassische ist: A und B brauchen X
und Y, ... A hat schon X, B schon Y.
Und ja, für beides gibt es Lösungen, ...
A. S. schrieb:> Also eher ungeeignet, wenn man ein RTOS hat und> trotzdem lieber Loop will.
Das verstehe ich nicht!
Habe mich schon recht viel mit den Protothreads beschäftigt.
Eben weil sie den Heap nicht so belasten wie z.B. FreeRTOS
Aber dein Argument kommt nicht bei mir an.
Was meinst du damit?
Arduino Fanboy D. schrieb:> A. S. schrieb:>> Also eher ungeeignet, wenn man ein RTOS hat und>> trotzdem lieber Loop will.>> Das verstehe ich nicht!> Habe mich schon recht viel mit den Protothreads beschäftigt.> Eben weil sie den Heap nicht so belasten wie z.B. FreeRTOS> Aber dein Argument kommt nicht bei mir an.>> Was meinst du damit?
In diesem Thread geht es um die Loop vs. Multitasking. Dann kam das
Argument, dass Loop/FSM mit Switch/case eher verkappte Gotos seien.
Hierauf kamen von Stefan die Dunkelthreads. Diese bilden aber eher ein
Multitasking per Loop nach also Loop/FSM. Sie sind also (wie Du auch
schreibst) eine Art RTOS und keine Verbesserung der Loop.
Stefan F. schrieb:> S. R. schrieb:>> Es hindert dich niemand daran, die FSM in einer Metasprache zu>> erstellen, aus der dann eine numerische, automatisch generierte Liste>> von Zuständen entsteht.>> Zum Beispiel die Protothreads von Adam Dunkels.
Der wesentliche Punkt ist, dass einige hier, selbst bei unendlicher
Rechenleistung und optimalem RTOS, die Aufgabe lieber in
Loop/FSM/Switch/Case formulieren als in Tasks mit
Events,Nachrichtenpuffer und Co. Nicht unbedingt Kommunikation (Sio,
Ethernet), Display oder UI, aber z.B. Steuerungsaufgaben.
A. S. schrieb:> In diesem Thread geht es um die Loop vs. Multitasking.
Naja, eigentlich ging es um Literatur zu Design-Pattern. Die
Echtzeit-Vs-Multitasking-Fraktion hat den Thread nur gekapert.
A. S. schrieb:> Der wesentliche Punkt ist, dass einige hier, selbst bei> unendlicher Rechenleistung und optimalem RTOS, die Aufgabe> lieber in Loop/FSM/Switch/Case formulieren als in Tasks mit> Events,Nachrichtenpuffer und Co.
Diese Sicht der Dinge bezweifle ich dann doch mal sehr stark, denn im
Gegensatz zu dir sehe ich hier durchaus ein Augenmaß.
Eine klassische Loop hat aus meiner Sicht einige wesentliche Vorteile
gegenüber dem, was ein RTOS bietet. Einerseits ist es sparsamer,
andererseits lassen sich Echtzeitgarantien durch die feste Struktur
relativ leicht formal verifizieren (wenn man sauber implementiert).
Wenn man nicht mehr um jedes Byte im RAM kämpfen muss, keine formale
Verifikation braucht, aber dafür ein System mit hoher Komplexität und
Dynamik bauen will, dann nimmt man ein RTOS. Das ist aber nicht gerade
die ATtiny-Klasse.
A. S. schrieb:> In diesem Thread geht es um die Loop vs. Multitasking.
Ich sehe das Ausschlusskriterium nicht.
Loop ist für mich erstmal nur eine Schleife.
Von mir aus "hier" auch eine Endlosschleife.
Grundsätzlich benötigt jeder Prozess und auch jede Task eine solche
Endlosschleife.
(Ausnahmen mag es geben)
Auf den kleinen µC gibts eben (z.B. mangels OS) nur einen Prozess.
Und auch keine Tasks im engeren Sinn, mangels RAM.
Also nur eine einzige Endloschleife. Loop.
Die Protothreads bieten die Chance auch diesen Zwergen mehrere
Endlosschleifen aufzudrücken. Ohne den sonst nötigen Stack und damit
auch Heap Bedarf.
S. R. schrieb:> Wenn man nicht mehr um jedes Byte im RAM kämpfen muss, keine formale> Verifikation braucht, aber dafür ein System mit hoher Komplexität und> Dynamik bauen will, dann nimmt man ein RTOS
Das hört sich so an, als seiest Du der Meinung, dass die Loop eher ein
Kompromiss bei knappen Ressourcen ist. Ich hingegen sehe die Loop im
Vorteil, wenn man aus dem vollen schöpfen kann. Und genau das ist der
strittige Punkt des TO:
Andre schrieb:> Denke die Zeiten in denen noch mit einer "Main Control Loop" versucht> wurde solche Systeme zum Laufen zu bekommen, sollten lange vorbei sein.Walter T. schrieb:> Die Echtzeit-Vs-Multitasking-Fraktion hat den Thread nur gekapert.
Siehe TO.
Christopher J. schrieb:> Task A hat höchste Priorität und wartet auf Task C> Task B hat mittlere Priorität und wartet auf A> Task C hat niedrigste Priorität>> Das wäre jetzt normalerweise ein Deadlock.> Durch priority inheritance bekommt aber jetzt C die Priorität von A> vererbt (weil ja A auf C wartet), wodurch zunächst C laufen kann und> danach dann A und anschließend B.
C kann doch auch einfach so laufen, denn A und B sind ja blockiert. Ein
Problem hat man erst, wenn B nicht wartet. Dann wird der nämlich
ausgeführt und sorgt dafür, dass der eigentlich höherpriore A nicht
ausgeführt werden kann, weil der wiederum auf C wartet, der aber von B
verdrängt wird.
Der beschriebene Fall war aber eigentlich ein anderer, nach meinem
Verständnis. Man stelle sich zwei Tasks vor, die jeweils zwei Ressourcen
gleichzeitig benötigen:
Task A acquiriert Ressource 1 (z.B. durch einen Mutex-Lock)
Task B acquiriert Ressource 2
Task A will Ressource 2 auch, muss aber warten, weil Task B sie schon
hat
Task B will Ressource 1 auch, muss aber warten, weil Task A sie schon
hat
So blockieren sich die beiden Tasks gegenseitig.
Deadlock oder Verklemmung bezeichnet in der Informatik einen Zustand, bei dem eine zyklische Wartesituation zwischen mehreren Prozessen auftritt, wobei jeder beteiligte Prozess auf die Freigabe von Betriebsmitteln wartet, die ein anderer beteiligter Prozess bereits exklusiv belegt hat. Eine andere Form der Blockierung von Prozessen ist der Livelock.
2
3
Beispielsweise kann einem Prozess p1 der Bildschirm zugeteilt worden sein. Gleichzeitig benötigt p1 allerdings den Drucker. Auf der anderen Seite ist der Drucker dem Prozess p2 zugeteilt, der wiederum den Bildschirm fordert. Ein Beispiel für eine Verklemmung aus dem realen Leben ist eine Straßenkreuzung, an der von allen vier Seiten Autos gekommen sind und nun (die Regel rechts vor links vorausgesetzt) darauf warten, dass das jeweils rechts wartende Auto zuerst fährt. Ein weiteres Beispiel ist das Philosophenproblem.
4
5
Eine andere Form der Blockierung von Prozessen, die wie ein Deadlock die weitere Ausführung des Programms verhindert, ist der Livelock. Er bezeichnet eine Form der Blockierung zweier oder mehrerer Prozesse, die im Unterschied zum Deadlock nicht in einem Zustand verharren, sondern ständig zwischen mehreren Zuständen wechseln, aus denen sie nicht mehr entkommen können. Jeder einzelne Prozess verharrt also nicht für immer im Wartezustand, sondern ist weiterhin aktiv, kann aber auch nicht seine Aufgabe abarbeiten.[3]
6
7
Anschaulich kann man sich zum Livelock zwei Personen vorstellen, die sich in einem Gang entgegenkommen und fortwährend versuchen, einander in der gleichen (Absolut-)Richtung auszuweichen, und sich gerade dadurch immer gegenseitig blockieren. Beim Deadlock würden sich – in dieser Veranschaulichung bleibend – die zwei Personen nur gegenüberstehen und jeweils darauf warten, dass die andere beiseite geht, was nicht geschieht.
A. S. schrieb:> Das hört sich so an, als seiest Du der Meinung, dass die Loop eher ein> Kompromiss bei knappen Ressourcen ist. Ich hingegen sehe die Loop im> Vorteil, wenn man aus dem vollen schöpfen kann.
Jaein. Es ist die - aus meiner Sicht - optimale Lösung, wenn man formale
Verifizierbarkeit braucht oder auf extrem knappen Systemen arbeitet. Das
ist keine Kompromisslösung.
Aber eine zentrale Hauptschleife ist für komplexe Systeme mit vielen
Komponenten relativ schlecht wartbar. Man muss einen recht
einschränkenden Programmierstil durchziehen (es darf nichts blockieren,
also muss alles als Automat realisiert werden) und damit wird der Code
nicht unbedingt lesbarer.
Ab einer gewissen Komplexität sind Tasks aus meiner Sicht eleganter,
solange nicht das Gesamtsystem formal verifiziert werden muss. In den
meisten Systemen müssen nicht alle Teile knappe Echtzeitanforderungen
erfüllen, und dann führt ein RTOS mit präemptivem Scheduler eher zu
verständlicherem Code.
Ich behaupte mal (ohne Beweis und wissenschaftliche Grundlage), dass
jedes Problem eine bestimmte inhärente Komplexität hat und daher jede
Lösung diese Komplexität irgendwie abbilden muss. In einem RTOS kann man
vieles wunderschön als Tasks abbilden, in OOP wunderschön als
Objekthierarchie - aber die Komplexität taucht dann im Zusammenspiel der
Komponenten wieder auf.
Am Ende sucht man sich mit dem Design die Teilbereiche aus, die man
zukünftig ständig debuggen wird.
Bernd K. schrieb:> Egon D. schrieb:>> Schleifen sind verkappte Rücksprünge und daher>> natürlich verboten;>> Was für ein Käse!
???
> Wenn ich eine Schleife brauche um über irgendwas> zu iterieren verwende ich natürlich eine Schleife.
Hmm.
Bedeutet also: Wenn Du eine Berechnung ausführen musst,
die -- angenommen -- 10s dauert, dann führst Du diese
Berechnung am Stück aus und lässt währenddessen alle
Aktoren ungebremst an die Anschläge krachen?
Sicher nicht.
> Es ist bei so einem Konzept lediglich verboten> blockierend auf etwas zu WARTEN!
Nein.
Es ist verboten, Programmteile zu haben, die die
geforderte Laufzeitgarantie verletzen. Warten verletzt
die Laufzeitgarantie mit Sicherheit -- aber das kann
auch ganz schnell auf eine (endliche) Schleife zutreffen,
wenn die Zahl der Schleifendurchläufe groß genug ist.
Dein etwas rustikal formulierter Einwand hat aber
einen wahren Kern: Es ist nicht absolut zwingend, dass
man Schleifen verbietet. Schleifen, deren Zeitbedarf
man zuverlässig nach oben abschätzen kann, darf man
unter Umständen zulassen.
Egon D. schrieb:> Schleifen, deren Zeitbedarf> man zuverlässig nach oben abschätzen kann, darf man> unter Umständen zulassen.
Das hat er genau so gemeint. Missverstehen kann man das nur, wenn man es
missverstehen will, um etwas zum meckern zu haben. Die Meister dieser
Zunft haben sich bei mikrocontroller.net vereint.
Egon D. schrieb:> Hmm.> Bedeutet also: Wenn Du eine Berechnung ausführen musst,> die -- angenommen -- 10s dauert, dann führst Du diese> Berechnung am Stück aus und lässt währenddessen alle> Aktoren ungebremst an die Anschläge krachen?
Nein. Ich habe gesagt wenn ich eine Schleife brauche dann benutze ich
eine Schleife, nicht mehr und nicht weniger, denn es ist Käse zu sagen
alle Arten von Schleifen seien pauschal verboten oder seien immer ein
verkapptes irgendwas, denn das ist nicht der Punkt um den es bei einem
solchen Entwurfsmuster eigentlich geht.
Wenn Du also Regeln formulieren willst dann formuliere sie von Anfang an
präzise und schreib nicht erst irgendwas das in der Form überhaupt nicht
zu verallgemeinern und daher einfach falsch ist.
Vielen Dank für die rege Diskussion so weit!
Als ich davon schrieb, dass in einer FSM keine strukturierten
Programmanweisungen möglich sind, ging es natürlich nicht um die
Programmierung innerhalb eines Zustandes, sondern die Strukturierung
über die verschiedenen Zustände hinweg.
Ein kleines Beispiel aus einer modernen Sprache, die Nebenläufigkeit
direkt unterstützt (Single-Threaded!), mag das verdeutlichen:
1
async function boringCycle(n, depth) {
2
const partialDepth = (i) => (i+1)/n * depth;
3
4
for (i = 0; i < n; i++) {
5
if (i > 0) await sleep(0.5);
6
await moveAbsolute(-partialDepth(i));
7
await sleep(0.5);
8
await moveAbsolute(0.0);
9
}
10
}
In dieser asynchronen Funktion (die andere asynchrone Funktionen
natürlich nicht blockiert), bleibt die Schleifenstruktur sichtbar,
obwohl der Ablauf sequentiell formuliert ist.
Wird diese einfache Funktion mit einer FSM umgesetzt, wird die Schleife
über mehrere Zustände verteilt und ist nicht mehr direkt sichtbar.
Der Implementierungsaufwand für eine FSM ist merklich größer und die
Wartbarkeit einer FSM-Implementierung ist deutlich schlechter.
Suchender schrieb:> Ein kleines Beispiel aus einer modernen Sprache, die Nebenläufigkeit> direkt unterstützt (Single-Threaded!), mag das verdeutlichen:
Das sieht aber mehr so aus wie reine Abläufe. Also erst dies solange,
dann das bis, dann n Mal jenes.
Da ist der Task-ansatz doch gut und eine Loop/statemachine ohne Vorteil.
Suchender schrieb:> Ein kleines Beispiel aus einer modernen Sprache, die Nebenläufigkeit> direkt unterstützt (Single-Threaded!), mag das verdeutlichen:
Die Sprache ist mir unbekannt.
Also stütze ich mich hier auf die mir bekannten.
Ein kleines Beispiel mag verdeutlichen, dass sich sowas auch mit den
Protothreads umsetzen lässt:
1
constbytetaster=4;// Taster zwischen Pin und GND
2
constbyteled=13;// Led zwischen Pin und GND
3
constbytezyklen=5;// Anzahl Blinker
4
constunsignedlonginterval=500;// ms
5
6
boolblinkAnforderung=false;// Merker für Blink Anforderung
Suchender schrieb:> Der Implementierungsaufwand für eine FSM ist merklich größer und die> Wartbarkeit einer FSM-Implementierung ist deutlich schlechter.
Och, dazu gibt es doch Generatoren, oder man baut sich einen. Es muss
nicht unbedingt SDL
https://de.wikipedia.org/wiki/Specification_and_Description_Language
sein.
Aktuell ist es unter dem Begriff DSL
https://de.wikipedia.org/wiki/Dom%C3%A4nenspezifische_Sprache wieder
modern, sich intern oder extern kleine Helferlein zu bauen, um auf einer
höheren Abstraktionsebene ein Problem angehen zu können. Neu ist das
wahrlich nicht. Ob man sein Helferlein einen Code-Generator oder eine
DSL nennt, es bleibt das Gleiche.
Bernd K. schrieb:> Egon D. schrieb:>> Hmm.>> Bedeutet also: Wenn Du eine Berechnung ausführen musst,>> die -- angenommen -- 10s dauert, dann führst Du diese>> Berechnung am Stück aus und lässt währenddessen alle>> Aktoren ungebremst an die Anschläge krachen?>> Nein. Ich habe gesagt wenn ich eine Schleife brauche> dann benutze ich eine Schleife, nicht mehr und nicht> weniger,
Richtig. Das habe ich gelesen und verstanden.
Wenn also diese von Dir benutzte Schleife 10^7 Durchläufe
braucht und 10s Rechenzeit frisst, dann findet genau das
statt, was ich oben beschrieb.
Wie soll man sachlich mit Dir diskutieren, wenn Du einer-
seits eine bestimmte Voraussetzung aufstellst ("Wenn ich
eine Schleife brauche, nutze ich eine Schleife!") und
andererseits eine direkte logische Folgerung aus dieser
Voraussetzung als falsch verwirfst?
> denn es ist Käse zu sagen alle Arten von Schleifen> seien pauschal verboten oder seien immer ein verkapptes> irgendwas, denn das ist nicht der Punkt um den es bei> einem solchen Entwurfsmuster eigentlich geht.>> Wenn Du also Regeln formulieren willst dann formuliere> sie von Anfang an präzise und schreib nicht erst irgendwas> das in der Form überhaupt nicht zu verallgemeinern und> daher einfach falsch ist.
Du wirst mir bitte nicht übelnehmen, dass ich Deine
künstliche Empörung lächerlch finde.
Ich habe etwas in der Mathematik Übliches und Wohlbekanntes
getan -- ich habe nämlich eine hinreichende Bedingung
formuliert. Diese lautet: Hinreichend für eine Laufzeit-
garantie ist das Verbot aller Rückwärtssprünge (was alle
lokalen Schleifen einschließt).
Diese Bedingung ist aber NICHT notwendig, das heißt: Sie
kann abgeschwächt werden.
Stefan F. schrieb:> Egon D. schrieb:>> Schleifen, deren Zeitbedarf man zuverlässig nach>> oben abschätzen kann, darf man unter Umständen>> zulassen.>> Das hat er genau so gemeint. Missverstehen kann man> das nur, wenn man es missverstehen will, um etwas> zum meckern zu haben.
Ganz im Gegenteil.
Ich möchte -- auch wenn es zu glauben schwerfällt --
niemanden absichtlich missverstehen. Ich möchte im
Gegenteil möglichst klar und deutlich formulieren,
in welchen Fragen Einigkeit herrscht, und zu welchen
Themen die Ansichten auseinandergehen.
Suchender schrieb:> Als ich davon schrieb, dass in einer FSM keine> strukturierten Programmanweisungen möglich sind,> ging es natürlich nicht um die Programmierung> innerhalb eines Zustandes, sondern die> Strukturierung über die verschiedenen Zustände> hinweg.
Das liegt letztlich im Begriff "strukturierte
Programmierung".
Das Fundament der Informatik ist ja, dass Programme
konkrete, maschinell ausführbare Formulierungen für
Algorithmen sind.
Algorithmen wiederum sind Vorschriften, die in endlich
vielen Schritten zum Ergebnis führen.
Eine Maschinensteuerung hat aber in diesem Sinne kein
"Ergebnis"; die Frage, ob und wann das Programm
"terminiert", ist völlig gegenstandslos. Steuerungen
sind IHRER NATUR NACH reine Reiz-Reaktions-Schemata.
Schon der Begriff des Algorithmus ist darauf nicht
eingerichtet, und die üblichen Programmiersprachen sind
es noch viel weniger.
> Der Implementierungsaufwand für eine FSM ist merklich> größer und die Wartbarkeit einer FSM-Implementierung> ist deutlich schlechter.
Natürlich.
Es müsste ja eigenlich von selbst ins Auge springen,
dass künstliche Sprachen, die für das Implementieren
von ALGORITHMEN optimiert sind, nur umständlich für
das Implementieren von ENDLICHEN AUTOMATEN zu nutzen
sind.
Das bedeutet aber nicht, dass FSM an sich Mist sind.
Egon D. schrieb:> Ich möchte im> Gegenteil möglichst klar und deutlich formulieren,> in welchen Fragen Einigkeit herrscht, und zu welchen> Themen die Ansichten auseinandergehen.
Dafür gibt es einen Fachbegriff, den ich mir auch oft (zu Recht) anhören
muss: Elender Klugscheißer.
Stefan F. schrieb:> Egon D. schrieb:>> Ich möchte im Gegenteil möglichst klar und deutlich>> formulieren, in welchen Fragen Einigkeit herrscht,>> und zu welchen Themen die Ansichten auseinandergehen.>> Dafür gibt es einen Fachbegriff, den ich mir auch oft> (zu Recht) anhören muss: Elender Klugscheißer.
Richtig.
Der natürliche Lebensraum des Elenden Klugscheißers
sind Diskussionsforen mit gemäßigtem Klima; sie
unterscheiden sich in diesem Punkt von den Gemeinen
Trollen, deren Aktivität stark ansteigt, je frostiger
das Klima ist.
Egon D. schrieb:> Der natürliche Lebensraum des Elenden Klugscheißers> sind Diskussionsforen mit gemäßigtem Klima; sie> unterscheiden sich in diesem Punkt von den Gemeinen> Trollen, deren Aktivität stark ansteigt, je frostiger> das Klima ist.
Willst du damit ausdrücken, dass das wesentliche Unterscheidungsmerkmal
der Lebensraum ist, nicht das Verhalten?
S. R. schrieb:> Egon D. schrieb:>> Der natürliche Lebensraum des Elenden Klugscheißers>> sind Diskussionsforen mit gemäßigtem Klima; sie>> unterscheiden sich in diesem Punkt von den Gemeinen>> Trollen, deren Aktivität stark ansteigt, je frostiger>> das Klima ist.>> Willst du damit ausdrücken, dass das wesentliche> Unterscheidungsmerkmal der Lebensraum ist, nicht> das Verhalten?
Ich wollte eigentlich nur auf scherzhafte Weise aus-
drücken, dass ich Stefan in der Grundaussage ("Klug-
scheisser!") zustimme, (s)eine möglicherweise
beabsichtigte negative Wertung dieses Verhaltens aber
nicht teile.
Das Erwähnen der Trolle war nur Garnierung, die sich
gerade anbot.
Rolf M. schrieb:> C kann doch auch einfach so laufen, denn A und B sind ja blockiert. Ein> Problem hat man erst, wenn B nicht wartet. Dann wird der nämlich> ausgeführt und sorgt dafür, dass der eigentlich höherpriore A nicht> ausgeführt werden kann, weil der wiederum auf C wartet, der aber von B> verdrängt wird.
Ja, stimmt. Wenn sich B schlafen legt (d.h. auf A wartet), läuft
automatisch C. Das Beispiel war wohl eher suboptimal.
Arduino Fanboy D. schrieb:> Suchender schrieb:>> Ein kleines Beispiel aus einer modernen Sprache, die Nebenläufigkeit>> direkt unterstützt (Single-Threaded!), mag das verdeutlichen:>> Die Sprache ist mir unbekannt.
Das ist aktuelles Javascript. Rust bietet mit async/await mittlerweile
ebenfalls solche Hilfsmittel für asynchrone Funktionen ohne
(Thread-)Overhead. Allerdings ist das bisher leider noch auf den Desktop
beschränkt, d.h. eine no_std Implementierung steht noch aus.
Christopher J. schrieb:> Rolf M. schrieb:>> Das bringt dir aber für den genannten Deadlock nichts.>> Vielleicht hab ich es auch falsch verstanden aber hier mal meine> Auffassung des Problems:>> Task A hat höchste Priorität und wartet auf Task C> Task B hat mittlere Priorität und wartet auf A> Task C hat niedrigste Priorität>> Das wäre jetzt normalerweise ein Deadlock.
Vorsicht: Nein. Das ist ein lockout in Folge einer priority inversion.
Solange C irgendwann mal drankommt, wird die Verklemmung gelöst. Ein
deadlock ist eine nicht mehr auflösbare Situation. Das lässt sich durch
Resource Allocation Graphs veranschaulichen und auch formalisieren (wenn
geschlossene Kreise in solchen Graphen existieren, liegt ein deadlock
vor). Solange also C nicht direkt oder indirekt auf A warten muss, gibt
es keinen geschlossenen Kreis und damit keinen deadlock.
> Durch priority inheritance> bekommt aber jetzt C die Priorität von A vererbt (weil ja A auf C> wartet), wodurch zunächst C laufen kann und danach dann A und> anschließend B.
Richtig, damit wird dann die priority inversion aufgelöst (die Priorität
von A bestimmt dann am Ende des Tages den Gesamtumlauf, was man ja auch
intuitiv erwartet).
Als Variante zur priority inheritance gibt es auch noch das Priority
Ceiling Protocol zur Lösung dieser Situation.
Walter T. schrieb:> Marten Morten schrieb:>> Making Embedded Systems: Design Patterns for Great Software>> https://www.amazon.com/Making-Embedded-Systems-Patterns-Software/dp/1449302149/>> Ich habe es vor ein paar Jahren mal gelesen und war sehr enttäuscht.
Ich muss doch noch einmal auf das Buch zurückkommen. Weil ich auch von
anderer Stelle noch einmal auf das Buch gestoßen wurde, und ich damals
keine Notizen zum Buch gemacht habe, habe ich es in den vergangenen
Tagen noch einmal zu lesen angefangen (bin jetzt bei 2/3).
Das Buch ist besser, als ich es in Erinnerung habe. Vielleicht habe ich
es in meinem obigen Kommentar mit einem anderen Buch verwechselt, das
ich zur gleichen Zeit gelesen habe, vielleicht habe ich damals, als ich
es gelesen habe, noch nicht verstanden, was brauchbar ist, oder
vielleicht habe ich damals einfach nach etwas komplett anderem gesucht.
Lange Rede, kurzer Sinn: Das Buch ist doch ziemlich gut. Es werden
Design-Pattern auf hoher Ebene vorgestellt, während Hardware-Sachen eher
kurz angerissen werden. Das ist als Ansatz für jemanden, der in eine
Embedded-Firma einsteigt, absolut in Ordnung. Der Mensch wird ja kaum in
den ersten Wochen damit anfangen, die Low-Level-Treiber zu schreiben.
Auch interessant: Das in diesem Buch beschriebene Vorgehen beim
Speichern und Darstellen von Fonts/Glyphen habe ich erst letztes Jahr,
sehr brauchbar als U8G2 implementiert kennengelernt. Inklusive
RLE-Komprimierung.
Vom dem Buch ist eine lange Leseprobe als PDF im Netz auffindbar. Unterm
Strich ist es sehr lesenswert.