Forum: Mikrocontroller und Digitale Elektronik ESp32 Multithreading


von Thorsten M. (Gast)


Lesenswert?

Moin,

auch wenn alles mit einem 1s Timer Int läuft, mich reizt jetzt die 
Auslagerung der Datenerfassung eines ADC115 auf den anderen Core. Ich 
habe mir das angeschhaut wie man mit xcreate... Tasks zeugt aber 
versteht folgendes nicht:

1. Wann wird eine task aufgerufen?
2. wie wird sie verlassen?
3. wie oft wird sie aufgerufen?

In Beispielen stehen da ständig Endlos Schleifen drin. Wozu das? Ohne 
stürzt der ESp32 ab.

Ich muss 1x die Sekunde daten in Arrays einschreiben. Das dauert fast 
150ms.  Das soll nicht mehr das Hauptprogramm auf Core1 machen sondern 
der andere Kern. Core 1 greift nur atomar lesend auf Variablen zu, d.h. 
Core 0 kann da reinschhreiben.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thorsten M. schrieb:
> Wann wird eine task aufgerufen?

Die Task-Funktion wird aufgerufen sobald man den Task erzeugt hat.

Thorsten M. schrieb:
> wie wird sie verlassen?

Nie, bei FreeRTOS sollten Tasks nicht zurück kehren sondern in einer 
Endlosschleife laufen.

Thorsten M. schrieb:
> wie oft wird sie aufgerufen?

Genau so oft wie du xTaskCreate aufrufst, also typischerweise 1x.

Thorsten M. schrieb:
> In Beispielen stehen da ständig Endlos Schleifen drin. Wozu das? Ohne
> stürzt der ESp32 ab.

Weil man unter FreeRTOS Threads nicht beenden kann. Ist auch meistens 
nicht nötig. Du lässt den Task halt endlos laufen.

von Thorsten M. (Gast)


Lesenswert?

Ok .. ich will aber keine delay 1000 da reinschreiben muessen. Die Task 
wird ja sicherlich vom scheduler unterbrochen. Sonst saesse der Core ja 
fest. Wie kriege ich es hin, dass die Task nur alle 1s Daten holt?

von Harry L. (mysth)


Lesenswert?

Niklas G. schrieb:
> Weil man unter FreeRTOS Threads nicht beenden kann.

Natürlich kann man Tasks auch wieder beenden, und das ist auch durchaus 
nichts Ungewöhnliches.

Seite 53:
https://www.freertos.org/fr-content-src/uploads/2018/07/FreeRTOS_Reference_Manual_V10.0.0.pdf

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thorsten M. schrieb:
> Ok .. ich will aber keine delay 1000 da reinschreiben muessen.

Warum nicht?

Thorsten M. schrieb:
> Wie kriege ich es hin, dass die Task nur alle 1s Daten holt?

Mit Delay, oder präziser mit dem Timer API:

https://www.freertos.org/RTOS-software-timer.html

Die Timer Callbacks laufen aber alle in einem Thread.

PS:
Wenn du deinen Task nicht permanent benötigst, und die Datenerfassung 
ein-und ausschalten möchtest, kannst du den Task (in der Endlosschleife) 
zwischenzeitlich schlafen legen und bei Bedarf aufwecken. Das geht u.a. 
mit dem Notification API:

https://www.freertos.org/RTOS-task-notifications.html

Das reduziert die Leistungsaufnahme.

von Thorsten M. (Gast)


Lesenswert?

Also quasi jede Sekunde die Task wrzeugen und mit vdeleteTask wieder 
verlassen? Und das alles von Core 1 aus? Die spielt dann ja von allein 
denke ich

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Harry L. schrieb:
> Natürlich kann man Tasks auch wieder beenden, und das ist auch durchaus
> nichts Ungewöhnliches.

Ja richtig, habe was verwechselt. Nur zurückkehren darf die 
Task-Funktion nicht, weil der vPortTaskWrapper vom ESP32 danach einen 
abort() hat.

von Harry L. (mysth)


Lesenswert?

Thorsten M. schrieb:
> Also quasi jede Sekunde die Task wrzeugen und mit vdeleteTask wieder
> verlassen?

Nein!

Einfach mit delay schlafen legen.
Der Sheduler kümmert sich um den Rest.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thorsten M. schrieb:
> Also quasi jede Sekunde die Task wrzeugen und mit vdeleteTask
> wieder
> verlassen? Und das alles von Core 1 aus? Die spielt dann ja von allein
> denke ich

Nein, den Task permanent laufen lassen. Entweder per Delay zwischendurch 
schlafen legen oder per Software Timer und xTaskNotify aufwecken. Tasks 
ständig zu erzeugen und wieder löschen macht wenig Sinn.

von Thorsten M. (Gast)


Lesenswert?

Ich muss mir das erstmal bildlich aufmalen. Der delay(1000) in der Tasks 
blockiert also den Core nicht? Die Datensammlung laeuft rund um die Uhr 
bei mir. Die Arrays liegenn im RTC Ram und werden nur gelesen von der 
loop im Arduino.

von Harry L. (mysth)


Lesenswert?

Thorsten M. schrieb:
> Der delay(1000) in der Tasks
> blockiert also den Core nicht?

Nein.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thorsten M. schrieb:
> Der delay(1000) in der Tasks blockiert also den Core nicht?

Nein, FreeRTOS führt dann andere Tasks aus, oder eben den Idle-Task. Ein 
schlafender Task verbraucht keine Rechenzeit (und keine Energie!). Das 
kannst du am PC ausprobieren: Starte in einem Programm so viele Threads 
wie CPU-Cores existieren (oder auch viel mehr), die alle nur Sleep 
aufrufen. Friert der PC ein? Geht die CPU-Last auf 100%?

von Thorsten M. (Gast)


Lesenswert?

Ok, ich bedanke mich erstmal. Viele Texte im Netz vergessen es, dass man 
erstmal das Ganze verstehen muss, bevor man sich mit den Details 
befasst.

Also das ginge auch:

Core 1 (der wo alles drauf läuft)):

Global:
3x arrays

loop () {

   if (Flags.1s)
     erzeuge task Datensammeln

}

task datensammeln() {

  Hole 1 Datum pro Durchlauf und schreibe es ein
  Bilde Mittelwerte
  zerstöre task;
}

alternativ wird die task nur einmal im setup erzeugt und dann

task datensammeln() {

  while (1) {
  Hole 1 Datum pro Durchlauf und schreibe es ein
  Bilde Mittelwerte
  delay(1000)
}
}

von Thorsten M. (Gast)


Lesenswert?

Niklas G. schrieb:
> Nein, FreeRTOS führt dann andere Tasks aus, oder eben den Idle-Task.

da liest man noch etwas von yield() und vdelay(), die benutzt werden 
sollen, da delay scheinbar doch blockiert.

https://www.esp32.com/viewtopic.php?t=8944#:~:text=This%20is%20vTaskDelay%20%28pdMS_TO_TICKS%20%2810%29%29%20a%20delay%20of,pdMS_TO_TICKS%20%28X%29%20which%20will%20do%20it%20for%20you.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Was erhoffst du dir davon den Task ständig zu zerstören und neu zu 
erstellen? Das ist eine Menge Overhead.

FreeRTOS verteilt die Tasks automatisch auf die beiden Cores. Es kann 
dir recht egal sein was genau auf Core 0 und 1 läuft.

von Thorsten M. (Gast)


Lesenswert?

Niklas G. schrieb:
> Was erhoffst du dir davon den Task ständig zu zerstören und neu zu
> erstellen? Das ist eine Menge Overhead.

Bei einer CPU, die 240 Mio Ops/s macht ist mir das völlig wumpe..... 
aber ich werde wohl die bessere Möglichkeit wählen. Ich nutze kein 
FreeRTOS, nur die beidden Funktionen daraus. Mein programm existiert 
schon und ist sehr gross.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thorsten M. schrieb:
> da delay scheinbar doch blockiert.

Ich denke du meinst vTaskDelay? Ja, das blockiert, im Sinne von dass der 
Scheduler diesen Task nicht mehr ausführt bis die Zeit abläuft. Der CPU 
Kern ist dann frei für andere Tasks.

Thorsten M. schrieb:
> Bei einer CPU, die 240 Mio Ops/s macht ist mir das völlig wumpe

Du machst dir ja schon Gedanken beide Cores zu benutzen, also scheinen 
einmal 240 Mio OPs nicht zu reichen...?

Thorsten M. schrieb:
> Ich nutze kein FreeRTOS, nur die beidden Funktionen daraus

Auf den ESP32 musst du FreeRTOS benutzen. Das läuft immer im 
Hintergrund. ESP-IDF startet das automatisch.

von Thorsten M. (Gast)


Lesenswert?

Niklas G. schrieb:
> Du machst dir ja schon Gedanken beide Cores zu benutzen, also scheinen
> einmal 240 Mio OPs nicht zu reichen...?

Kannst ja mal reinschauen wo für das alles gut ist, der Link ist noch 
ein paar Tage gültig, habe das im Gast wlan laufen. Der ESP32 Firebeetle 
steuert mittlerweile so viele Relais und Geräte... ist schon ein geiles 
Teilchen.

http://l11vzu256z3bfz2j.myfritz.net/abfrage?pass=myesp32

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Thorsten M. schrieb:
>  da delay scheinbar doch blockiert.

Welche eine rege Fantasie!
Einbildung, statt Doku lesen...

Tipp:
Man kann auch in den Quellcode schauen, wenn man wissen will was delay() 
tut.
https://github.com/espressif/arduino-esp32/blob/1a7962ece8a4c6ffa1d64c5a86ed8ee58dde10ba/cores/esp32/esp32-hal-misc.c#L176

Er liegt auch auf deinem Rechner.

Beitrag #7419465 wurde von einem Moderator gelöscht.
von Thorsten M. (Gast)


Angehängte Dateien:

Lesenswert?

So, alles ausprobiert, chatGPT schreibt auch den Code und das sogar 
richtig.
Das Teil ist einfach nur genial, wenn man alles nochmal überprüft...
vTaskDelay ist übrigens richtig!

von Mike R. (thesealion)


Lesenswert?

Thorsten M. schrieb:
> So, alles ausprobiert, chatGPT schreibt auch den Code und das sogar
> richtig.

Aber nur wenn der Kopierer auch weiß, dass er den Semaphore vorher auch 
noch erzeugen muss. Ansonsten gibt es Schiffbruch.

von Thorsten M. (Gast)


Lesenswert?

Mike R. schrieb:
> Aber nur wenn der Kopierer auch weiß, dass er den Semaphore vorher auch
> noch erzeugen muss. Ansonsten gibt es Schiffbruch.

Nein, das nicht aber ein Reset :-) Überdies ist der Reset die Antwort 
des ESP32 auf alles, ähnlich "42".

In meiner Awendung läuft tasking nicht, vermutlich weil ich die Hardware 
Timer benutze und ne Menge Interfaces. In einer Beispeilanwendung klappt 
alles prima. Wenn FReeRtOS dann auch nur diese API nutzen,. die zb für 
die Timer nur soft Timer vorsieht.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thorsten M. schrieb:
> Nein, das nicht aber ein Reset

Haha, bei Race Conditions passieren irgendwie unvorhersehbaren, gerne 
auch unbemerkte, Probleme. Irgendwann macht das Programm nicht 
reproduzierbar irgendwas komisches und keiner weiß warum. Ein reset wäre 
ja schön, da bemerkt man wenigstens dass was schief läuft. Aber woher 
soll der ESP32 wissen dass da eine Race Condition vorliegt?

Thorsten M. schrieb:
> In meiner Awendung läuft tasking nicht

Wie hast du das hinbekommen? Das ESP-IDF (welches ja Teil des Arduino 
ESP32 Framework ist) startet automatisch FreeRTOS und den Scheduler. 
Ohne das funktioniert weder das ESP-IDF, noch das Arduino Framework, 
noch die WiFi-Funktion.

Thorsten M. schrieb:
> die zb für die Timer nur soft Timer vorsieht.

Die Soft Timer funktionieren ebenfalls nur wenn FreeRTOS "richtig" 
läuft.

PS: Von mehreren Threads aus auf I²C zugreifen (und das per Semaphore 
absichern) finde ich übrigens nicht besonders clever, weil I²C ja 
ziemlich langsam ist und somit mehrere Threads für längere Zeit 
blockiert werden und nichts anderes tun können. Ich würde das eher von 
einem einzelnen Thread aus machen und diesen asynchron mit den anderen 
Threads kommunizieren lassen.

von Alexander (alecxs)


Lesenswert?

Arduino F. schrieb:
> Man kann auch in den Quellcode schauen, wenn man wissen will was delay()
> tut.

Aha, es wird vTaskDelay() aufgerufen und durch portTICK_PERIOD_MS 
dividiert.
https://github.com/espressif/arduino-esp32/blob/31d22e6/cores/esp32/esp32-hal-misc.c#L209

portTICK_PERIOD_MS = 1000 / configTICK_RATE_HZ
https://github.com/espressif/esp-idf/blob/36a5a71/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h#L116

configTICK_RATE_HZ = 100
https://github.com/espressif/esp-idf/blob/36a5a71/components/freertos/Kconfig#L37

Also ist portTICK_PERIOD_MS = 10 ms. Wenn ich delay(1) aufrufe, wird 
dann 1 durch 10 dividiert. Da es ein uint32_t ist kommt da = 0 heraus.

Also ist
delay(1) = 0
delay(2) = 0
delay(3) = 0
delay(4) = 0
delay(5) = 0
delay(6) = 0
delay(7) = 0
delay(8) = 0
delay(9) = 0
gar nicht anwendbar!

Kleinstes zulässiges delay(10) ist also 10 ms.

: Bearbeitet durch User
von Alexander (alecxs)


Lesenswert?

Ich bräuchte hier noch mal Hilfe. Ich hab vermutlich irgendwo ein 
Problem mit einer Race Condition, und ich vermute es liegt am Timing. 
Ich hab mir von ChatGPT ein non-blocking delayMicroseconds() basteln 
lassen, hab aber keine Ahnung ob es funktioniert. Hauptproblem ist, dass 
diesselbe Funktion auf verschiedenen Cores aus verschiedenen Tasks 
aufgerufen wird, daher ist für jede Instanz ein eigener Timer notwendig. 
Momentan wird bei jedem Aufruf ein neuer Timer erstellt, das erzeugt 
unnötigen Overhead. Versuche den Timer außerhalb der Funktion anzulegen 
scheitern an den parallelen Instanzen. Vielleicht kann sich das mal 
jemand mit wirklich Ahnnung angucken?
1
// non-blocking delayMicroseconds()
2
void delay_us(uint32_t us) {
3
    TaskHandle_t thisTask = xTaskGetCurrentTaskHandle();
4
    // Timer callback: notify the sleeping task
5
    auto timerCallback = [](void* arg) {
6
        TaskHandle_t task = static_cast<TaskHandle_t>(arg);
7
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
8
        vTaskNotifyGiveFromISR(task, &xHigherPriorityTaskWoken);
9
        if (xHigherPriorityTaskWoken) {
10
            portYIELD_FROM_ISR();
11
        }
12
    };
13
    // Create one-shot esp_timer
14
    esp_timer_handle_t timer;
15
    esp_timer_create_args_t timer_args = {
16
        .callback = timerCallback,
17
        .arg = (void*)thisTask,
18
        .dispatch_method = ESP_TIMER_TASK,
19
        .name = "delay_us_timer"
20
    };
21
    esp_timer_create(&timer_args, &timer);
22
    esp_timer_start_once(timer, us);  // Delay in microseconds
23
    // Wait for notification (puts task to sleep)
24
    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
25
    esp_timer_delete(timer);
26
}

von Nemopuk (nemopuk)


Lesenswert?

Alexander schrieb:
> hab aber keine Ahnung ob es funktioniert

Probiere es aus!

> Momentan wird bei jedem Aufruf ein neuer Timer erstellt, das erzeugt unnötigen 
Overhead. Versuche den Timer außerhalb der Funktion anzulegen scheitern an den 
parallelen Instanzen.

Wenn es anders nicht geht, ist der Overhead offenbar nicht unnötig, 
sondern notwendig.

Hat das Betriebssystem keine fertige Lösung für diese Aufgabe? Ich kann 
mir nicht vorstellen, daß jeder Anwendungsprogrammierer dieses Rad für 
sich neu erfinden muss. In der Doku von vTaskDelay() steht nichts von 
solchen Einschränkungen.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Alexander schrieb:
> Ich hab vermutlich irgendwo ein
> Problem mit einer Race Condition

Hat denn dein aufzuweckender Task auch die höchste Priorität? Sonst wird 
der Scheduler vermutlich nicht sofort zu diesem wechseln, und dann 
stimmt die Zeit nicht. Die normale Granularität des Schedulers ist bei 
den ESP32 IIRC auf 10ms eingestellt.

von Alexander (alecxs)


Lesenswert?

Nemopuk schrieb:
> Probiere es aus!

Ich hab verschiedene Tests mit Debugausgaben über Serial.print gemacht, 
die Funktion scheint im so darstellbaren Millisekundenbereich ordentlich 
zu timen. Allerdings sagt das nichts über den Mikrosekundenbereich aus.

Mein kleinstes delay ist 1ms. Mal funktioniert es und mal nicht (der 
Task, nicht das delay), hab die Vermutung das hier der Overhead 
ausbremst.

: Bearbeitet durch User
von Richie (mikro123)


Lesenswert?

Niklas G. schrieb:
> Alexander schrieb:
>> Ich hab vermutlich irgendwo ein
>> Problem mit einer Race Condition


So ganz klar ist mir jetzt nicht, was genau da im Einzelnen laufen soll.

Aber wenn es nur darum geht, dass die Datenerfassungs-Tasks jede Sekunde 
laufen sollen, dann nimm doch einfach die Funktion xTaskDelayUntil().
Den Heckmeck mit den Timern brauchst Du dann gar nicht.

Die Task-Prioritäten musst Du allerdings auch so beachten. Die Funktion 
xTaskDelayUntil() setzt den Task nur in den Zustand Ready. Der Scheduler 
läßt den nur laufen, wenn er (mit) die höchste Priorität aller Ready 
Tasks hat.

In der FreeRTOS Config bestimmt übrigens der Parameter 
configTICK_RATE_HZ die Tick-Rate. Oft ist die auf 100Hz eingestellt.

von Alexander (alecxs)


Lesenswert?

Richie schrieb:
> Oft ist die auf 100Hz eingestellt.

Das ist ja das Problem. Siehe weiter oben.

Richie schrieb:
> Aber wenn es nur darum geht, dass die Datenerfassungs-Tasks jede Sekunde
> laufen sollen, dann nimm doch einfach die Funktion xTaskDelayUntil().

Jede Millisekunde. Auch hier kleinstes zulässiges Delay 10ms (wegen 
ganzzahliger Division)

https://docs.espressif.com/projects/esp-idf/en/v4.4/esp32/api-reference/system/freertos.html#_CPPv415xTaskDelayUntilPC10TickType_tK10TickType_t

von Alexander (alecxs)


Lesenswert?

Ich glaub ich hab das Problem gefunden. Ich hab eine globale Variable 
mit Namen `timer`. Die Funktion hat einen `esp_timer_handle_t timer`. 
Ich benenne um...

von Sebastian W. (wangnick)


Lesenswert?

Alexander schrieb:
> ein non-blocking delayMicroseconds()

Was soll das "non-blocking" im Kontext von FreeRtos denn sein? Die 
Zeitscheiben bleiben ja trotzdem 10ms lang. Warum nicht eine simple 
Schleife, die auf das Verstreichen der benötigten Mikrosekunden "busy" 
wartet?

LG, Sebastian

: Bearbeitet durch User
von Alexander (alecxs)


Lesenswert?

Non-blocking ist das Gegenteil von busy-waiting. Während der delay Pause 
soll CPU frei sein.

von Falk B. (falk)


Lesenswert?

Alexander schrieb:
> Non-blocking ist das Gegenteil von busy-waiting. Während der delay Pause
> soll CPU frei sein.

AUTSCH!

http://kamelopedia.net/wiki/Denglisch

von Rick (rick)


Lesenswert?

Alexander schrieb:
> Ich hab mir von ChatGPT ein non-blocking delayMicroseconds() basteln
> lassen, hab aber keine Ahnung ob es funktioniert.
Ja, davon hat ChatGPT auch keine Ahnung, es schwafelt nur beeindruckend.

Warum schaust Du nicht in die entsprechende Anleitung (RTFM) und 
verwendest die mitgelieferte vTaskDelay()?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Alexander schrieb:
> Während der delay Pause soll CPU frei sein.

Wie viele Mikrosekunden sind es denn? Was soll die CPU in den paar 
Mikrosekunden denn alles schaffen? Ist es nicht möglich, die Aufgabe in 
Hardware laufen zu lassen (PWM, DMA, ...)?

von Alexander (alecxs)


Lesenswert?

Rick schrieb:
> Warum schaust Du nicht in die entsprechende Anleitung (RTFM) und
> verwendest die mitgelieferte vTaskDelay()?

Würdest Du mir bitte zeigen wo in dieser entsprechenden Anleitung auf 
das Problem eingegangen wird (RTFT)?

Niklas G. schrieb:
> Wie viele Mikrosekunden sind es denn?

1ms = 1000µs sind beim ESP32 240000 Clock cycles. In der Zeit soll ein 
anderer Task was machen dürfen.

Falk B. schrieb:
> AUTSCH!

Ich finde ja "während der `delay()` Pause" ist korrektes deutsch, und 
über Dein Denglisch in so manchen KiCad T̶h̶r̶e̶a̶d̶s̶ Themen wollen wir 
nicht streiten :P

Rick schrieb:
> Ja, davon hat ChatGPT auch keine Ahnung, es schwafelt nur beeindruckend.

ChatGPT ist zumindest auf das Problem eingegangen nachdem ich erklärt 
habe warum vTaskDelay() nicht brauchbar ist. Und schlägt nun vor den 
Overhead (~100µs) zu reduzieren mit einem Lazy-Init Timer in einer 
Klasse, und einem Makro Wrapper der für jede Instanz automatisch eine 
neue Funktion deklariert so dass man `delay_us()` wie bisher aufrufen 
kann. Gefällt mir aber nicht so, da das dann zur Compile Time passiert. 
Dann lieber die Tick-Rate erhöhen.

Die Funktion selbst war ja auch letztendlich nicht das Problem, der 
Fehler mit der vermeintlichen Race Condition lag beim Anwender 
(Namenskollision global/statisch `timer`)

: Bearbeitet durch User
von Sebastian W. (wangnick)


Lesenswert?

Alexander schrieb:
> Non-blocking ist das Gegenteil von busy-waiting. Während der delay Pause
> soll CPU frei sein.

Alexander schrieb:
> In der Zeit soll ein anderer Task was machen dürfen.

von Alexander (alecxs)


Lesenswert?

= Multithreading

von Sebastian W. (wangnick)


Lesenswert?

Sorry, da war ich noch mitten im Schreiben.

Alexander schrieb:
> Non-blocking ist das Gegenteil von busy-waiting. Während der delay Pause
> soll CPU frei sein.

Alexander schrieb:
> In der Zeit soll ein anderer Task was machen dürfen.

Wenn du während des Wartens zu einem anderen Task schalten lässt, wie 
soll FreeRtos dann. nach Ablauf der Wartezeit zu dem Wartetask 
zurückschalten? Dazu braucht es ein Ereignis, entweder einen Tick des 
Schedulers (nur alle 10ms), oder einen Interrupt, oder die Kooperation 
des anderen Tasks.

Die Timer-Interruptlösung hat dir ChatGPT aufgedröselt.

Für die Schedulerlösung müsstest du wohl tatsächlich die Tickrate 
erhöhen.

Kooperativ könnte noch funktionieren, je nachdem wie der "andere Task" 
strukturiert ist, also ob der "andere Task" häufig und regelmäßig genug 
deinen Wartetask über eine Semaphore oder so "anpingen" kann, und dieser 
dann prüft, ob die Wartezeit abgelaufen ist, und falls nicht die 
Kontrolle wieder "kurz" an den "anderen Task" abgibt.

LG, Sebastian

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.