YANOS - Yet Another Narrow Operating System Hallo Zusammen, die erste Frage ist vielleicht - och nee, warum denn schon wieder eins? Das habe ich mich auch gefragt. Vorher bin ich immer mit meinen timer tasks und einer mehr oder weniger grossen Statusmaschine in der mainloop ausgekommen. Dann wurde ich bei einem Projekt gezwungen, zwei nicht kooperative Tasks gemeinsam laufen zu lassen. Dazu habe ich einen simplen Taskswitcher geschrieben. Dann kam der Wunsch auf, die Rechenzeit nicht mehr 50:50, sondern zur Laufzeit je nach Bedarf aufzuteilen. Das ging auch noch recht einfach. Das Projekt wuchs und wuchs. Mailboxen und Messages wurden auf Applikationsebene implementiert. Ein dritter Task, der nur ab und an mal laufen sollte, wurde angedacht. Die Lockingmechanismen fuer konkurierende Hardwarezugriffe wurden auch immer komplizierter. Da jetzt noch weiter irgendwie dran rumzufrickeln machte wenig Sinn. Die Zeit war also reif fuer ein OS. Kein Problem, gibt ja genug. Aber die kleinen koennen meist nicht mit nicht kooperativen Tasks umgehen. Die die es koennen arbeiten oft prioritaetsbasiert. Damit unsere beiden Tasks damit laufen, muessten sie die gleiche Prioritaet bekommen. Dann laufen sie aber wieder 50:50. Die naechst Besseren, die anhand der Prioritaet Laufzeitverteilungen vornehmen, sind dann allerdings schon ziemlich fett und behaebig. So entstand das Xte OS. Da ich so einen Ansatz bislang noch nicht gesehen habe, stelle ich das mal ins Forum. Das ist zwar sehr auf eine bestimmte Anwendung optimiert, aber vielleicht kann das ja trotzdem jemand von Euch gebrauchen. Gruss Udo
servus, hast du vielelciht ein beispielprogramm das die anwendung zeigt bei der hand und magst es heir hineinstellen? danke hansl
Für welche Prozessor ist das Ganze denn gedacht? Habe diesbezüglich im Quelltext nichts gefunden. Und mit dem Assemblerschnipseln wirds wohl nicht plattformunabhängig sein.
Hallo Hans, vor ca. 2 Wochen habe ich den Code auf das grosse Projekt losgelassen. Hat auch sehr gut funktioniert. Diesen Source darf/moechte ich aber nicht posten (waere auch viel zu viel). Ich habe aber noch meinen Testcode, den ich fuer die Entwicklung von Yanos verwendet habe. Das kannst Du Dir gerne mal anschauen. Aber Achtung - das ist lediglich zum Testen und anschliessend fuer die Muelltonne geschrieben worden. Hallo Thomas, das laeuft auf einem M32. Ist wohl eher selten im Forum. Sollte aber egal sein, da es bis auf den Scheduler reines C ist. Portierungen eines Schedulers auf die hier im Forum hauptsaechlich verwendeten Prozessoren habe ich schon mehrere gesehen. In einer aelteren Version hatte ich den Scheduler auf die klassische Weise implementiert. Da kann man den Assemblercode ja nahezu 1:1 von Prozessor zu Prozessor uebernehmen. Hier habe ich diese halbwegs vorhandene plattformunabhaengigkeit bewusst verlassen, um auf Geschwindigkeit zu optimieren. Mit jetzt knapp ueber 5us (ohne OS-overhead) habe ich die Threadwechselzeit nahezu halbiert. Gruss Udo BTW: Gibt hier noch andere M16/M32 Programmierer die stctx/ldctx verwenden? Es kommt mir so vor, als haette ich diese Befehle irgendwie vergewaltigt.....
uCler wrote: > Die Lockingmechanismen fuer > konkurierende Hardwarezugriffe wurden auch immer komplizierter. Wie hast Du denn das gelöst ? Bei einer Mainloop sind solche Probleme ja sehr selten, da ja alles immer der Reihe nach abläuft. Aber mit Deinem OS müssen ja solche Probleme alle Nase lang auftreten, da ja alles virtuell parallel ist. Insbesondere auf 8-Bittern ist ja auch Datenmurx quasi vorprogrammiert, bei allen globalen Variablen, die mehrbytig sind (Zeitscheibe haut genau dazwischen, macht nen neuen Wert und man hat dann ein neues Byte + ein altes Byte). Das ist es auch, was mich vor einem OS zurückschrecken läßt. Die möglichen Deadlock und Datenmurx-Probleme sind mit einem OS ja kaum beherrschbar. Die Datenzugriffe zwischen Main und Interrupts zu sichern (Interruptsperre), geht ja noch. Aber wenn plötzlich jede Maintask die andere unterbrechen kann, sieht ja keiner mehr durch. Ich hab z.B. mehrere Statemachines, wo zu Anfang alle Eingänge per SPI eingelesen werden, dann verarbeiten das die Statemachines und dann wird wieder alles per SPI ausgegeben. Das kann aber nur funktionieren, wenn die Daten während eines kompletten Zyklus konstant bleiben. Bzw. es können auch zwischenzeitlich Fehlerstates auftreten, die keinesfalls ausgegeben werden dürfen. Erst wenn der abschließende Fehlerchecker die Daten nochmal geprüft hat, das kein gefährlicher Zustand entstehen kann, dann dürfen sie angelegt werden. Peter
Peter Dannegger wrote: > Das ist es auch, was mich vor einem OS zurückschrecken läßt. > > Die möglichen Deadlock und Datenmurx-Probleme sind mit einem OS ja kaum > beherrschbar. > > > Die Datenzugriffe zwischen Main und Interrupts zu sichern > (Interruptsperre), geht ja noch. > Aber wenn plötzlich jede Maintask die andere unterbrechen kann, sieht ja > keiner mehr durch. Dafür gibt es Synchronisationsmechanismen wie Semaphoren und Queues. Richtig angewendet ist damit der "Murx" gut beherrschbar. > Ich hab z.B. mehrere Statemachines, wo zu Anfang alle Eingänge per SPI > eingelesen werden, dann verarbeiten das die Statemachines und dann wird > wieder alles per SPI ausgegeben. Das kann aber nur funktionieren, wenn > die Daten während eines kompletten Zyklus konstant bleiben. Wenn kein anderer Task in diesen Daten herumpfuscht (warum sollte er auch?), dann gibt es da keine Probleme.
Andreas Schwarz wrote: > Dafür gibt es Synchronisationsmechanismen wie Semaphoren und Queues. > Richtig angewendet ist damit der "Murx" gut beherrschbar. Das sind dann Notlösungen, die wieder zusätzliche Ressourcen verbrauchen, statt das Problem zu vermeiden. Besonders heimtückisch sind die Queues. Wenn man da nicht 101%-ig garantieren kann, daß der empfangende Prozess immer schneller als der sendende ist, läuft die Queue über. Oder sie ist sehr groß und läuft sehr voll und dann arbeitet der empfangende Prozess noch völlig veraltete Daten ab und z.B. Dein Regelkreis schwingt. Ich habe daher bessere Erfahrungen mit einem Datenpuffer für genau einen Datensatz gemacht. Wenn dann mal der Empfänger nicht nachkommt, überschreibt einfach der Sender den Puffer mit den aktuelleren Daten, also z.B. ein alter AD-Wandler Wert geht verloren und alles läuft problemlos weiter. Peter
Peter Dannegger wrote: > Andreas Schwarz wrote: > >> Dafür gibt es Synchronisationsmechanismen wie Semaphoren und Queues. >> Richtig angewendet ist damit der "Murx" gut beherrschbar. > > > Das sind dann Notlösungen, die wieder zusätzliche Ressourcen > verbrauchen, statt das Problem zu vermeiden. Das sind "Lösungen", keine Notlösungen. > Besonders heimtückisch sind die Queues. > Wenn man da nicht 101%-ig garantieren kann, daß der empfangende Prozess > immer schneller als der sendende ist, läuft die Queue über. > Oder sie ist sehr groß und läuft sehr voll und dann arbeitet der > empfangende Prozess noch völlig veraltete Daten ab und z.B. Dein > Regelkreis schwingt. > > Ich habe daher bessere Erfahrungen mit einem Datenpuffer für genau einen > Datensatz gemacht. Und was hindert dich daran das mit einem RTOS genauso zu machen? Für sowas einen Queue zu verwenden ist natürlich sinnlos. > Wenn dann mal der Empfänger nicht nachkommt, überschreibt einfach der > Sender den Puffer mit den aktuelleren Daten, also z.B. ein alter > AD-Wandler Wert geht verloren und alles läuft problemlos weiter. Wieso nicht gleich den Messwert im Regelungs-Task einlesen? Nur weil man einen Hammer (RTOS) hat darf nicht alles wie ein Nagel (Task) aussehen.
Andreas Schwarz wrote: > Das sind "Lösungen", keine Notlösungen. Für mich setzen Lösungen immer bei der Ursache an und Notlösungen bekämpfen aber nur die Wirkung. > Wieso nicht gleich den Messwert im Regelungs-Task einlesen? Weil ich keine Zeit verschwenden will. Der ADC-Task ist freilaufend und kann mehrere Eingänge einlesen, glätten und in Puffern ablegen. Und jede Task, die einen Wert braucht, liest ihn sofort aus dem Puffer. Ich habe sehr gute Erfahrungen damit gemacht, daß ich alle Tasks in der Mainloop in einer eindeutig definierten Reihenfolge ohne gegenseitige Unterbrechung aufrufe. Damit ergibt sich eine sehr geringe Fehleranfälligkeit und sehr stabiles Arbeiten. Natürlich dürfen die Tasks keine Zeit vergeuden, jede Task bricht sofort ab, wenn sie grad nichts zu tun hat. Und Prozesse, die erst nach einer bestimmten Wartezeit ausgeführt werden dürfen, übergebe ich dem Scheduler. Der ist auch eine Task in der Mainloop, d.h. wird auch nur zu ganz eindeutigen Zeiten ausgeführt. Es ist halt nur ne klitzekleine Umstellung in der Programmierweise erforderlich, Bedingungen werden nicht wartend, sondern abweisend programmiert. Also nicht: warte bis Bedingung wahr, sondern: breche ab solange Bedingung nicht wahr. Peter
Peter Dannegger wrote: > Andreas Schwarz wrote: > >> Wieso nicht gleich den Messwert im Regelungs-Task einlesen? > > Weil ich keine Zeit verschwenden will. > Der ADC-Task ist freilaufend und kann mehrere Eingänge einlesen, glätten > und in Puffern ablegen. > Und jede Task, die einen Wert braucht, liest ihn sofort aus dem Puffer. Wenn du kooperatives (also kein preemtives Scheduling verwendest), dann gibt es damit grundsätzlich kein Problem, weil der Kontextwechsel erst stattfindet wenn der ADC-Task fertig ist und sich schlafen legt. Wenn du preemtives Scheduling verwendest (was in deinem Fall wenig Sinn macht), dann kannst du eine critical section verwenden um sicherzustellen dass der ADC-Task beim Schreiben der globalen Variablen nicht preemtiv unterbrochen werden kann: taskENTER_CRITICAL(); globaler_adcwert = adcwert; taskEXIT_CRITICAL(); > Natürlich dürfen die Tasks keine Zeit vergeuden, jede Task bricht sofort > ab, wenn sie grad nichts zu tun hat. > Und Prozesse, die erst nach einer bestimmten Wartezeit ausgeführt werden > dürfen, übergebe ich dem Scheduler. Der ist auch eine Task in der > Mainloop, d.h. wird auch nur zu ganz eindeutigen Zeiten ausgeführt. > > > Es ist halt nur ne klitzekleine Umstellung in der Programmierweise > erforderlich, Bedingungen werden nicht wartend, sondern abweisend > programmiert. > Also nicht: warte bis Bedingung wahr, sondern: breche ab solange > Bedingung nicht wahr. Damit machst du ja all das von Hand was dir ein kooperatives OS abnehmen kann. Statt dem Scheduler zu sagen wann die Funktion das nächste Mal aufgerufen werden möchte und zu returnen, hast du bei einem OS für jeden Task eine eigene Endlosschleife, und wenn es nichts zu tun gibt weil du z.B. auf den nächsten Abtastzeitpunkt für den ADC oder die Regelung wartest, rufst du sleep_until(t + 100) auf. Und zusätzlich hast du z.B. eine komfortable Möglichkeit über Queues Nachrichten zu verschicken, ohne dass du in jedem Empfängertask if(!neue_daten_vorhanden) return; machen musst, usw.
Meine Meinung ist, dass ein multitaskingfähiges OS in einem ROM ein totaler Overhead ist. Es sind ja alle Prozesse und Funktionen bekannt, ein OS zu verwenden ist eigentlich nur ein Grund, ineffizient zu programmieren. Anders sieht es aus, wenn zum Erstellungszeitpunkt "unbekannte" Prozesse später auch geladen und entladen werden sollen. Dann ist ein OS eine saubere Schnittstelle, gegen die auch nichts spricht. Zum Probieren kann man das auch im ROM machen... Jörg
> Die Lockingmechanismen fuer > konkurierende Hardwarezugriffe wurden auch immer komplizierter. Wie hast Du denn das gelöst ? Hallo Peter, kleines Vorher/Nachher Beispiel aus der Praxis. Als NVRam setzen wir FRam ein. Das haengt ebenso am IIC wie die RTC und ein Temperaturfuehler. Zur Vermeidung von Konflikten musste der IIC-Code an eine gemeinsame Stelle. Um das System besser zu verstehen - Neben den OS-Tasks laufen noch 3 harte Realtime-Tasks (Timer Interrupts). Im 1ms Task laufen nur SW-Timer - Laufzeit vernachlaessigbar. Im 10ms Task laeuft im Wesentlichen das PID - in diesem Fall ein Touchscreen. Wenn man mit 8 Fingern drauf rumtrommelt steigt die Rechenzeit auf ca. 1ms, also ca. 10%. Im 100ms Task laeuft neben einer SW-Uhr im Wesentlichen die IIC Kommunikation. Die Gehaeuseinnentemperatur brauchen wir seit der Umstellung von STN auf TFT eigentlich nicht mehr. Sie wurde ohnehin nur alle paar Minuten gelesen. Auf die RTC wird nur beim Uhr stellen schreibend zugegriffen. Um die IIC Zugriffe zu minimieren wird im Betrieb aus der SW-Uhr gelesen. Bleibt das FRam. Grosse Datenmengen werden auf CF oder MMC gehalten. Das ist aber relativ lahm und unsicher bei power fail. Fuer Statusbytes und Parameterbloecke ist das NVRam da. Das habe ich segmentiert in Bytes, Worte, Longs und unterschiedlich grosse Bloecke. Frage war, wie gross darf ich den groessten Block machen, um Echtzeit zu garantieren. Aus dem Bauch raus habe ich mal maximal 50% fuer die harte Echtzeit angenommen. Datentransfer auf den beiden CAN-Bussen und der andere Kram, den ich oben nicht genannt habe, machen etwa 10% aus. Bleiben also grobe Kante 30ms fuer die groessten Bloecke. Schreibt also eine Applikation einen grossen Block ins Shadow-RAM ist kurz darauf der 100ms Task fuer maximal 30ms beschaeftigt - und 30 mal kommt der OS_Timer_Tick nicht durch. Das fuehrte dann zu folgenden, lustigen Fehlern. Normalerweise antwortet ein Modul am CAN-Bus innerhalb von 5ms. Der timeout wurde auf 20ms gesetzt. Das geht auch 100000 Mal gut. Aber wir hatte alle paar Tage mal einen timeout. Immer dann, wenn ein Task auf eine Antwort wartete, waerend der andere vorsichtshalber mal den kompletten Geraetestatus abspeicherte, um im Fall des Falles nach einem Powerfail evtl. an der gleichen Stelle weitermachen zu koennen (schreibt sich jetzt schnell - die Suche war es nicht). So - was tun? Timeout verlaengern? Bloecke verkuerzen? Retry Mechanismus? Anderswie zurechtfrickeln? Oder eben ein OS anstelle des Taskswitchers einsetzen (siehe meinen Ausgangspost). Jetzt ist alles ganz einfach. Einzelne Bytes oder Worte werden direkt aus der Applikation heraus geschrieben. Bloecke gehen nach wie vor uebers Shadow-Ram. Der ganze IIC-Code ist in einem OS Task gekapselt. Ueber Signale bekommt der mitgeteilt, ob er die Uhr stellen, einen Block ins FRam schreiben oder sonstwas auf dem IIC-Bus anstellen soll. Liegt nichts an, ist dieser Task tot. An dieser Stelle sieht man dann auch, warum ich den OS_Timer_Tick unbedingt bei 1ms lassen wollte. Der 100ms Task ist jetzt praktisch leer - die SW-Uhr braucht so gut wie keine Rechenzeit. Ueber den CAN-Bus hat das Board als Master volle Kontrolle, und der Touch ist im Normalbetrieb in Ruhe. So stehen fuer die OS-Tasks knapp 98% an Rechenleistung zur Verfuegung, und so im 5ms-Bereich kann man jetzt sogar bei den OS-Tasks von weicher Echtzeit reden. Puuh - viel Text. Ein weiteres Beispiel nur noch in Stichworten. Es ist jetzt relativ einfach, gleichzeitig mehrere Files zu oeffnen, und quasi gleichzeitig zu lesen oder zu schreiben. Gruss Udo
Joerg Wolfram wrote: > Meine Meinung ist, dass ein multitaskingfähiges OS in einem ROM ein > totaler Overhead ist. Es sind ja alle Prozesse und Funktionen bekannt, > ein OS zu verwenden ist eigentlich nur ein Grund, ineffizient zu > programmieren. Anders sieht es aus, wenn zum Erstellungszeitpunkt > "unbekannte" Prozesse später auch geladen und entladen werden sollen. Ich verstehe nicht wieso das ein Kriterium sein soll - die Vorteile eines RTOS, nämlich dass es einem abnimmt was Peter und viele andere von Hand machen, haben nichts damit zu tun ob Prozesse zur Laufzeit hinzugefügt/entfernt werden sollen. Das würde ja auch die Echtzeitfähigkeit und damit das "RT" in RTOS kaputtmachen.
Hallo Joerg, ich habe hier 'nur' zwei Tasks. Und die sind mir auch seit Monaten bekannt. Aber die sind nicht kooperativ. Wie soll ich die denn laufen lassen? Wenn Du etwas effizienteres kennst wie diese Minimalversion eines OS, dann wuerde ich mich freuen, wenn Du mir das mitteilst. Gruss Udo
@uCler >ich habe hier 'nur' zwei Tasks. Und die sind mir auch seit Monaten >bekannt. Aber die sind nicht kooperativ. Wie soll ich die denn laufen >lassen? Wieso nicht kooperativ? Schlecht programmiert? MfG Falk
uCler wrote: ... > Der ganze IIC-Code ist in einem OS Task gekapselt. ... Ich verstehe ehrlich gesagt überhaupt nicht, wo da das OS hilft. Was bedeutet "I2C ist ein OS-Task" praktisch gesehen ? Ich hätte I2C in seinen Interrupthandler gepackt und gut is. Dann noch ein Struct definieren, in dem die Slaveadresse, Datenpointer und Datenlänge abgelegt werden und los geht der Interrupt. Die Tasks, die dann I2C machen wollen, gucken nach, ob dieser Struct frei ist und starten dann I2C. Oder man legt ein Array an (für jede Task ein Eintrag), das der I2C-Interrupt abklappert. > Puuh - viel Text. Ein weiteres Beispiel nur noch in Stichworten. Es ist > jetzt relativ einfach, gleichzeitig mehrere Files zu oeffnen, und quasi > gleichzeitig zu lesen oder zu schreiben. Hmm, Files öffnet man doch per Filehandler. Auch in nem Single-Task-DOS kann ich mehrere Files öffnen (soviel, wie Handler frei sind). Peter P.S.: Ein Kollege von mir, der den CAN-Bus programmiert, wollte auch gerne eine maximale Latenzzeit von 2ms haben. Ich wollte aber einen 1-Wire Temperatursensor benutzen, was länger gedauert hätte. Ich hab ihm dann einfach nen Timerinterrupt geschrieben, der dann bitweise das 1-Wire gemacht hat und dann gings wieder. In nem Struct wurde abgelegt, wieviel Bytes nach dem 1-Wire-Reset zu senden sind, wieviel zu empfangen und wenn beide Zähler 0 waren, hat sich der Interrupt selber disabled. Ich arbeite sehr gerne mit Interrupts.
Auch wenn ich jetzt alle Zusammenhänge nicht kenne, versuche ich mal zu schreiben, wie ich an die Sache herangehen würde. Das erste Problem sind die nichtkooperativen Tasks. Sowas sollte es eigentlich nicht geben, ausser sie wurden von einem anderen System mehr oder weniger übernommen. Da es jetzt ja funktioniert, scheinen sie ja vorher jede Menge Zeit nutzlos verbraten zu haben. Da muß ich Falk voll recht geben, so etwas kann nicht besonders gut programmiert sein oder stammt bereits aus einem Kontext wo das nichts ausmachte. Manchmal werden auch Dinge in Interruptroutinen verfrachtet, die dort nichts zu suchen haben. Muß zum Beispiel die Routine für das Touchpanel unbedingt im Interrupt laufen oder werden bloß über AD-Wandler die Koordinaten abgefragt und dann berechnet. In dem Fall könnte man vielleicht den ADC im 1ms-Interrupt abfragen und die Ergebnisse in den Speicher schreiben. Die eigentliche Berechnung der Koordinaten kann dann im Hauptprogramm erfolgen. Meiner Meinung nach ist es besser, über ein Zählregister kleinere Aufgaben im schnelleren Interrupt mit zu machen und dafür eine Interruptquelle weniger zu haben. Ich programmiere viel in C, aber auf den 8-Bit Controllern bin ich damit überhaupt nicht warm geworden. Hier halte ich einen guten Makroassembler und ein paar passende Bibliotheken für die bessere Wahl. Ich will damit jetzt keinen Glaubenskrieg auslösen wegen Portabilität und so weiter, aber bis jetzt ist bei mir eigentlich bei jedem notwendigen Systemwechsel (warum auch immer) nur die grundsätzliche Funktionalität des Programms geblieben, weil man viele Dinge schon lange anders machen wollte... Gruß Jörg
Peter Dannegger wrote: > Ein Kollege von mir, der den CAN-Bus programmiert, wollte auch gerne > eine maximale Latenzzeit von 2ms haben. > Ich wollte aber einen 1-Wire Temperatursensor benutzen, was länger > gedauert hätte. > Ich hab ihm dann einfach nen Timerinterrupt geschrieben, der dann > bitweise das 1-Wire gemacht hat und dann gings wieder. Es gibt immer eine Möglichkeit etwas in kleine Zeitscheibchen zur Ausführung in Hauptschleife/Interrupt zu zerteilen, aber MANCHMAL ist der Aufwand einfach größer als wenn man dafür gleich ein RTOS verwendet. Wenn man allerdings eine ideologische Abneigung gegen RTOS mit Vorurteilen wie "langsam/großer Overhead/Notlösung" hat...
Andreas Schwarz wrote: > Es gibt immer eine Möglichkeit etwas in kleine Zeitscheibchen zur > Ausführung in Hauptschleife/Interrupt zu zerteilen, aber MANCHMAL ist > der Aufwand einfach größer als wenn man dafür gleich ein RTOS verwendet. > Wenn man allerdings eine ideologische Abneigung gegen RTOS mit > Vorurteilen wie "langsam/großer Overhead/Notlösung" hat... Ich habe leider bisher nirgends ein Beispiel gefunden, woran man die Vorteile eine RTOS aufm MC sehen konnte. Das 1-Wire ist ja gerade nicht für ein RTOS geeignet. Eine Bitzeit muß ja zwischen 60..120µs lang sein, d.h. man muß garantieren, daß eine zusätzliche Verzögerung höchstens 60µs betragen darf. Auf dem 8051 war das ganz einfach, der T0 wurde so eingestellt, daß nach 60µs der nächste Interrupt auftritt und ihm wurde Priorität 3 zugewiesen, d.h. er konnte sämtliche anderen Interrupts unterbrechen. Zusätzliche Latenzen enstehen nur dort, wo atomare Zugriffe auf Mehrbytevariablen erfolgen und die sind ja nur wenige µs lang. Ein RTOS mit nur max 60µs Latenz wäre dagegen auf dem 8051 unmöglich. Anbei mal der komplette 1-Wire Code. Peter
Frage an die RTOS-Experten: Könnt ihr einige Bücher / Fachartikel (vorzugsweise in deutscher Sprache, aber auch gerne in englisch) nennen, in denen die prinzipiellen Funktionsweisen eines RTOS und auch die Vorteile/Nachteile der verschiedenen Systeme (kooperativ, preemtiv usw.) erläutert werden? (sowohl für Einsteiger als auch für Fortgeschrittene) Vielen Dank.
Z.B. zu den Nachteilen von preemtiven Systemen: http://www.embedded.com/showArticle.jhtml?articleID=192701173
Andreas Schwarz wrote: > Z.B. zu den Nachteilen von preemtiven Systemen: > http://www.embedded.com/showArticle.jhtml?articleID=192701173 Da steht leider nichts neues für mich drin. Hast Du denn keinen Artikel pro RTOS ? Ich geb natürlich zu, daß ich mit Assembler angefangen hab (8051, AVR). Dadurch kann ich ziemlich gut einschätzen, wie teuer eine Task ist und wo ich sie dann einordnen muß (Interrupt, Mainloop, Scheduler). Peter
Erstmal musst du lernen zwischen preemtiven und kooperativen OS zu unterscheiden. Das was du von Hand machst ist exakt das was ein kooperatives OS macht.
Andreas Schwarz wrote: > Das was du von Hand machst ist exakt das was ein > kooperatives OS macht. Bloß mit dem großen Unterschied, daß ich genau bestimmen kann, in welcher Reihenfolge sie ausgeführt werden. Nur bei den Tasks, die ich dem Scheduler übergebe, weiß ich die Reihenfolge nicht mehr, aber bei denen ist es in der Regel auch nicht kritisch. Und nur diese Tasks haben dann auch den Scheduler-Overhead. Peter
Vielleicht reden wir auch aneinander vorbei, weil jeder eine andere Definition von "OS" hat. Eine Kombination aus Taskmanager, Scheduler etc. die ich an meine Tasks anpassen muß, ist für mich kein OS. Beim uC wäre das (für mich) ein monolithischer Kernel, dem ich die zu bearbeitenden Tasks als Tabelle vorgebe (Einsprungadresse, Intervall, Priorität). Die Schnittstellen sind definiert und alle Tasks (auch noch zu schreibende ;-) müssen sich daran halten. Der Overhead entsteht bei der Prozessumschaltung und im Task selbst, da zumindest beim AVR zur Laufzeit nur Resourcen im RAM (über Pointer) zugewiesen werden können. Richtig preemptives Multitasking geht meiner Meinung nach sowieso nur, wenn ein unkooperativer Task es nicht verhindern kann. Wenn aber jeder Task einfach die Interrupts abschalten kann, dann wird da wohl eher nix daraus. Oder es ist eben doch kein OS (nach meinem Verständnis) Gruß Jörg
Joerg Wolfram wrote: > Vielleicht reden wir auch aneinander vorbei, weil jeder eine andere > Definition von "OS" hat. Ein OS ist etwas, das Hardwareressourcen (=Rechenzeit) verwaltet und zuteilt. > Eine Kombination aus Taskmanager, Scheduler > etc. die ich an meine Tasks anpassen muß, ist für mich kein OS. Dass man den Scheduler an seine Tasks anpasst wäre so ungefähr Peters von-Hand-Modell. > Richtig preemptives Multitasking geht meiner Meinung nach sowieso nur, > wenn ein unkooperativer Task es nicht verhindern kann. Wenn aber jeder > Task einfach die Interrupts abschalten kann, dann wird da wohl eher nix > daraus. Anders geht es nicht, oder wie willst du sonst Hardwarezugriffe oder IPC realisieren, wenn überall der Scheduler dazwischenfunken kann?
Andreas Schwarz wrote: > Ein OS ist etwas, das Hardwareressourcen (=Rechenzeit) verwaltet und > zuteilt. Zu den Resourcen die verwaltet und verteilt werden müssen, gehören aber auch Speicher und Zugriff auf die Peripherie. Bei einem Controller ohne umschaltbare Registerbänke kann man den Tasks viele Register zur Verfügung stellen, die dann natürlich auch während der Taskumschaltung gerettet und restauriert werden müssen (=>braucht Zeit und Speicher). Oder man beschränkt sich auf wenige Register und der Task muss häufiger auf den Speicher zugreifen. > Anders geht es nicht, oder wie willst du sonst Hardwarezugriffe oder IPC > realisieren, wenn überall der Scheduler dazwischenfunken kann? Für Hardwarezugriffe gibt es OS-Routinen (z.B. BIOS). Und ein Task sollte die auch nutzen, anstelle selbst auf die Hardware zuzugreifen. Ich will auch nicht den Sinn eines OS in Frage stellen, aber um das Timing von quasiparallel ablaufenden Funktionen in einem Mikrocontroller zu verbessern, halte ich es für eine schlechte Wahl. Gruß Jörg
Joerg Wolfram wrote: > Andreas Schwarz wrote: > >> Ein OS ist etwas, das Hardwareressourcen (=Rechenzeit) verwaltet und >> zuteilt. > > Zu den Resourcen die verwaltet und verteilt werden müssen, gehören aber > auch Speicher und Zugriff auf die Peripherie. ... > Für Hardwarezugriffe gibt es OS-Routinen (z.B. BIOS). Und ein Task > sollte die auch nutzen, anstelle selbst auf die Hardware zuzugreifen. Die Unterscheidung zwischen Hardwaretreibern und normalen Tasks, wie man sie bei größeren Systemen (Linux, Windows) kennt, gibt es bei den kleinen Mikrocontroller-OSen nicht. Sie bestehen aus Scheduler, Timer, Synchronisationsmechanismen. Es geht nicht darum Hardware zu abstrahieren, sondern nur darum Rechenzeit zuzuteilen.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.