Hallo, ich und ein paar meiner Kommilitonene haben ein kleines Definitionsproblem. Wir hatten im letzen Semester Realzeitsysteme und es hieß, Preemtion sei, wenn eine Task unterbrochen werden kann, ohne dass sie fertig mit ihrer Aufgabe ist. Nun im neuen Semester, Mikrocontrollertechnik, nutzen wir das RTOS RTXtiny 166 von Keil. Die Tasks können vom BS unterbrochen werden, obwohl sie noch nicht fertig sind, was laut "unserer" Definition bedeutet es sei preemptive. Doch unser Dozent und Keil sagen es sei non-preemptive weil es nicht prioritätsgesteuert ist. Was ist denn nun preemption? Vielen Dank
http://de.wikipedia.org/wiki/Multitasking#Pr.C3.A4emptives_Multitasking http://en.wikipedia.org/wiki/Preemption_(computing) http://en.wikipedia.org/wiki/Nonpreemptive_multitasking http://www.uni-protokolle.de/Lexikon/Pr%E4emptives_Multitasking.html
> Was ist denn nun preemption?
Unterbrechung eines laufenden Tasks weil "seine Zeit abgelaufen ist",
also per Interrupt.
Es spielt keine Rolle, welcher Task nach der preemption als nächster
dran ist, es kann auch derselbe sein, obwohl ohne unterschiedliche
Prioritäten meist round robin passiert, also "der nächste (alle sind
gleich priorisiert also gleichwertig)" drankommt.
Non-preemptive heisst: Der Task gibt (per Aufruf einer Funktion) nur an
kontrollierten Stellen die Kontrolle an das Betriebssystem zurück. Das
vereinfacht die Programmierung, weil man weiß, daß bestimmte
Codeabschnitte (eben die zwischen den Aufrufen) nicht unterbrochen
werden können, also man kein locking braucht.
Das alte Windows 16 war non-preemtive und hat sehr gut funktioniert, die
Benutzertasks reagierten sauber, wer wollte konnte interruptgesteuerte
Treiber bauen die zwar den Benutzertask unterbrachen, aber ihn nie
aufriefen, also kein Problem waren. Win32 wurde preeemtive. Seit dem
hakt es an jeder Front, Kommandos werden verschluckt, gewisse Tasks
blockieren das System bis zum Stillstand und am fatalsten: Wenn man 2
Jobs gleichzeitig startet (z.B. Verzeichnisbauk kopieren unn Virenscan)
dauert es LÄNGER als wenn man sie strikt nacheinander ausführt, es ist
also genau das Gegenteil eines Multitasking-Systems.
Preemtive ist kein Segen, sondern erfordert mehr Verstand und Übersicht,
und wenn man die nicht hat, kommt so was wie bei Microsoft raus.
Non-preemtive zeigt unmittelbar wenn man als Programmierer ein yield
vergessen hat und ist i.A. einfacher zu realisieren. Natürlich hängt bei
non-preemtive das ganze System wenn man eine Endlosschleife ohne yiild
programmiert hat oder sie sich durch Fehler ergeben hat. Ein
"Ctrl-Alt-Del" der dann preemtive eingreift ist also nützlich.
Hallo, das ging ja schnell, genau das entspricht ja der ersten Definition. Dann hat Keil keinen Plan oder was? Die Wikilinks hatte ich auch gefunden, aber das bestätigt auch nur Def 1 und nicht das was Keil + Dozent meinen. Danke Gruß
MaWins Erklärung ist völlig korrekt, wobei man gern den Begriff "cooperative multitasking" statt "non-preemptive" verwendet. Schon weil sich daraus direkt das zugrunde liegende Verfahren ergibt: Die Task kooperiert explizit mit dem BS. Ob Prioritäten im Spiel sind oder nicht ist unerheblich - wobei ich allerdings bisher noch keinen RT-Kernel erblickt habe, in dem das nicht vorgesehen wäre. Schmeiss mal einen Link zu den merkwürdigen Aussagen von Keil rein.
Verwirrter schrieb: > Die Tasks können vom BS unterbrochen werden, > obwohl sie noch nicht fertig sind, was laut "unserer" Definition > bedeutet es sei preemptive. So stimmts aber dann doch nicht, denn auch in kooperativem Multitasking können Tasts vor Beendigung unterbrochen werden. Aber eben nur an Stellen, wo sie das explizit vorsehen. So gibt es bei solchen Kernels typischerweise eigens einen Kernelaufruf, der nichts anderes tut, als dem Kernel zu signaliseren, dass jetzt ggf. eine andere Task ran darf und die laufende Task wieder in die Warteschlange gestellt werden kann. Programme für kooperativem Multitasking können daher recht oft mitten in der Verarbeitung etliche solcher Aufrufe enthalten, um die Wartezeit anderer kritischerer Tasks gering zu halten. Denn die Reaktionszeit kritischer Tasks ist eben diese Zeit zwischen solchen Aufrufen (wozu auch viele andere Kernelaufrufe gehören können). Es liegt aber in der Natur der Sache, dass preemptives Multitasking stets mit mit Prioritäten einhergeht, während einfachere kooperative Kernels auch ohne Prioritäten Sinn ergeben können.
> RTOS RTXtiny 166 von Keil. Die Tasks können vom BS unterbrochen werden, > obwohl sie noch nicht fertig sind Wie geht es nach der Unterbrechung durch das BS weiter? Kann ein Context Switch erfolgen oder wird immer zu dem unterbrochenen Task zurückgekehrt? Laut Specs-Übersicht http://www.phaedsys.org/principals/keil/keil-RTOS/keilrtx166.html ist der preemptive Context Switch beim RTXtiny 166 nicht implementiert.
Helfer schrieb: > Laut Specs-Übersicht > http://www.phaedsys.org/principals/keil/keil-RTOS/keilrtx166.html ist > der preemptive Context Switch beim RTXtiny 166 nicht implementiert. Diese Übersicht macht klar, dass RTX166-Tiny ein einfaches kooperatives Multitasking ohne Prioritäten implementiert. D.h. die Task werden vermutlich zyklisch reihum aktiviert und reihen sich an entsprechenden Programmstellen freiwillig wieder hinten ein. > Wie geht es nach der Unterbrechung durch das BS weiter? Kann ein Context > Switch erfolgen oder wird immer zu dem unterbrochenen Task > zurückgekehrt? Die "Unterbrechung" sieht beispielsweise so aus:
1 | while (1) { |
2 | ... Arbeit für zig bis hunderte Mikrosekunden ... |
3 | RtxYield(); |
4 | }
|
Der (von mir erfundene) Kernelaufruf RtxYield erlaubt es dem Kernel, an dieser Stelle auf eine anderes Task umzuschalten. Die laufende Task landet dann am Ende der Wartschlange und kommt irgendwann später wieder dran.
@prx http://www.keil.com/rtx166tiny/ dritter Punkt : Preemptive task switching and task priorities are not supported >So stimmts aber dann doch nicht, denn auch in kooperativem Multitasking >können Tasts vor Beendigung unterbrochen werden. Aber eben nur an >Stellen, wo sie das explizit vorsehen. Ja, das passt mit der Definition überein, habs nur nicht komplett erklären können. @helfer >Wie geht es nach der Unterbrechung durch das BS weiter? Kann ein Context >Switch erfolgen oder wird immer zu dem unterbrochenen Task >zurückgekehrt? es kann, aber muss nicht, ein Context Switch erfolgen. gruß
Verwirrter schrieb: > @prx > http://www.keil.com/rtx166tiny/ > dritter Punkt : Preemptive task switching and task priorities are not > supported > Die Tasks können vom BS unterbrochen werden, > obwohl sie noch nicht fertig sind Das deckt sich aber nicht mit dem was ich dort lese. Da steht explizit, dass nur cooperatives Multitasking unterstützt wird. Was ja soviel heißt wie: Das Betriebssystem unterbricht von sich aus keinen Task, sondern der Task muss explizit an das Betriebssystem zurückgeben und so einen Taskwechsel erlauben. Aufpassen: Ein Task muss ja nicht 'fertig' sein, wenn er an das BS zurückgibt. Er kann ja auch einfach nur 'fair' sein und zb den Wagenrücklauf eines Druckers dazu benutzen, während des Ausdruckens einem anderen Task eine Chance zu geben. Der Task erlaubt daher, dass er unterbrochen wird, obwohl er noch nicht fertig ist. Das ist aber etwas anderes als wie wenn er gnadenlos vom BS nach Ablauf seiner Zeitscheibe interrupted wird.
Doch, der Task wird vom Betriebssystem unterbrochen, ohne dass er seine Rechenzeit freiwillig abgibt. Getestet mit Keil µVision 3 Gruß
Verwirrter schrieb: > Doch, der Task wird vom Betriebssystem unterbrochen, ohne dass er seine > Rechenzeit freiwillig abgibt. > *Getestet mit Keil µVision 3* Das steht nun aber für RTX 166-Tiny eindeutig im Widerspruch zu Keils Doku. Würde es entgegen eindeutiger Dokumentation Tasks an beliebiger Stelle durch andere Tasks (nicht Interrupts!) unterbrechten, dann wäre es unbenutzbar.
> Doch, der Task wird vom Betriebssystem unterbrochen, > ohne dass er seine Rechenzeit freiwillig abgibt WOFÜR unterbrochen ? Um einen Interrupt z.B. der Tatstuar zu behandeln, die die neue Taste in einen Buffer schreibt, und dann kehrt das Programm ZU DIESEM Task wieder zurück ? Das ist in Ordnung. Das sind verschiedene Ebenen. Interrupts sind immer erlaubt. Nur darf er halt nicht an andere Tasks auf derselben Ebene zurückkehren, mit der Gefahr, an die Stelle, an der er unterbrochen wurde, ein zweites mal zu gelangen, ohne daß der vorherige fortgesetzt wurde und dort "wieder verschwunden" ist und abgeräumt hat.
Also kurzes beispiel:
1 | void toggle_p1(void) _task_ 0 |
2 | {
|
3 | while(1) |
4 | {
|
5 | Toggle(p1); |
6 | }
|
7 | }
|
8 | |
9 | void toggle_p2(void) _task_ 1 |
10 | {
|
11 | while(1) |
12 | {
|
13 | Toggle(p2); |
14 | }
|
15 | }
|
ist nur Pseudocode unter der Annahme, dass task 0 und task 1 beim OS angemeldet sind. Dann sieht man mit dem Logik Analyzer, wie p1 5ms lang toggelt, und dann p2 5ms lang, dann wieder p1 usw. usf. Hoffe jetzt ist es etwas klarer. Gruß
> Hoffe jetzt ist es etwas klarer.
DAS ist preemtive multitasking.
Toggle wird von beiden Tasks durchlaufen
void Toggle(int pon)
{
port^=1<<pin;
}
void toggle_p1(void) task 0
{
while(1)
{
Toggle(p1);
}
}
void toggle_p2(void) task 1
{
while(1)
{
Toggle(p2);
}
}
Vermutlich ist in deiner RTX166 Tiny Konfiguration Round-Robin aktiv, sodass nach einem Timeout von 5ms der nächste Task aufgerufen wird. http://www.keil.com/support/man/docs/tr166/tr166_tasksched.htm http://www.keil.com/support/man/docs/tr166/tr166_roundrobin.htm Konfiguration siehe hier: http://www.keil.com/support/man/docs/tr166/tr166_config.htm
Ok, damit ist klar, dass der non-preemptive Kernel von Keil tatsächlich preemptive ist. Denn was hier passiert und in der Doku auch aufgeführt wird ist eben eine preemption, eine Unterbrechung der Task an von der Task nicht kontrollierbarer Stelle. Für mich wäre ein solcher Kernel ziemlich problematisch, weil man deshalb wie in einem preemptive Kernel programmierung muss, ohne aber über die dafür nötigen Synchronisationsmechanismen wie Semaphoren und Mutexe zu verfügen. Dieser Kernel kombiniert die Nachteile eines cooperative Kernels mit den Nachteilen eines preemptive Kernels. In einem echten non-preemptive Kernel kann sich darauf verlassen, dass zwischen zwei Kernel-Aufrufen mit Sicherheit nicht auf eine andere Task umgeschaltet wird. Weshalb man gemeinsam benutzte Daten innerhalb solcher Codesequenzen nicht durch Mutexe absichern muss und gemeinsam benutzte Funktionen nicht reentrant sein müssen, was die Programmierung erheblich vereinfacht und weit weniger fehlerträchtig ist. Beim Keil Kernel muss man das hingegen genau das tun, hat aber keine Mutexe zur Verfügung und kann sich daher nur über Abschaltung von Interrupts oder Zeitkalkulation (keine 5ms seit dem letzten Aufruf von os_wait) absichern. Das Risiko ist, dass man sich über kurz oder lang einen extrem schwer nachvollziehbaren Fehler durch Taskunterbrechung an ungünstiger Stelle einhandelt.
Als Beispiel für diese Problematik:
1 | void Toggle(int pon) |
2 | {
|
3 | // bewusst als 3 getrennte Operationen formuliert:
|
4 | int temp = port; // (1) |
5 | temp ^= 1<<pin; // (2) |
6 | port = temp; // (3) |
7 | }
|
8 | |
9 | void toggle_p1(void) task 0 |
10 | {
|
11 | while(1) |
12 | {
|
13 | Toggle(p1); |
14 | }
|
15 | }
|
16 | |
17 | void toggle_p2(void) task 1 |
18 | {
|
19 | while(1) |
20 | {
|
21 | Toggle(p2); |
22 | }
|
23 | }
|
Hier kann es nun passieren, dass Task 0 zwischen (1) und (3) unterbrochen wird und Task 1 zum Zuge kommt. Erstens muss Toggle nun reentant sein. Zweitens wird Task 0, wenn sie später wieder dran kommt, den alten vor vielen Millisekunden nach temp geladenen Wert in den Port schreiben und damit u.U. eine Änderung des zur anderen Task gehörenden Pins rückgängig machen. Dieser Code müsste also modifiziert werden, damit er unter allen Bedingungen funktioniert:
1 | void Toggle(int pon) |
2 | {
|
3 | disable_interrupts(); |
4 | // bewusst als 3 getrennte Operationen formuliert:
|
5 | int temp = port; // (1) |
6 | temp ^= 1<<pin; // (2) |
7 | port = temp; // (3) |
8 | enable_interrupts(); |
9 | }
|
A. K. schrieb: > In einem echten non-preemptive Kernel kann sich darauf verlassen, dass > zwischen zwei Kernel-Aufrufen mit Sicherheit nicht auf eine andere > Task umgeschaltet wird. Round Robin im RTX166 Tiny kann abgeschaltet werden (Round-Robin Timeout im Konfigurationsfile auf 0 setzen), dann dürfte nicht mehr an nicht kontrollierbarer Stelle auf eine andere Task umgeschaltet werden.
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.