Forum: Mikrocontroller und Digitale Elektronik Definition: Preemptive oder non-preemptive


von Verwirrter (Gast)


Lesenswert?

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

von Timmo H. (masterfx)


Lesenswert?


von MaWin (Gast)


Lesenswert?

> 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.

von Verwirrter (Gast)


Lesenswert?

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ß

von (prx) A. K. (prx)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Helfer (Gast)


Lesenswert?

> 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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Verwirrter (Gast)


Lesenswert?

@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ß

von Karl H. (kbuchegg)


Lesenswert?

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.

von Verwirrter (Gast)


Lesenswert?

Doch, der Task wird vom Betriebssystem unterbrochen, ohne dass er seine 
Rechenzeit freiwillig abgibt.
Getestet mit Keil µVision 3

Gruß

von (prx) A. K. (prx)


Lesenswert?

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.

von MaWin (Gast)


Lesenswert?

> 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.

von Verwirrter (Gast)


Lesenswert?

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ß

von (prx) A. K. (prx)


Lesenswert?

Was genau ist "Toggle"?

von Verwirrter (Gast)


Lesenswert?

pin Wackeln.

von MaWin (Gast)


Lesenswert?

> 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);
 }
}

von Michael (Gast)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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
}

von M. G. (looking)


Lesenswert?

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
Noch kein Account? Hier anmelden.