vTaskDelete(NULL) sometimes not working
Posted: Thu Jan 09, 2025 8:57 am
I have a use case where I have a constantly running task, which I occasionally need to stop and restart with a different configuration. To do this I check a flag in the task loop to let it terminate gracefully when requested, and then restart it from the main task as soon as it is in the eDeleted state.
The issue is that under certain circumstances, for example when requesting to stop the task from a WebServer, or by adding some delay before and after the call to resetTask, the task function will reach the end as expected, but it will stay in the eReady state, which means it will not get restarted by the main task. This means that the call to vTaskDelete(NULL) either blocks indefinitely, or does not put the task in the eDeleted state.
What is happening, why does it sometimes work and sometimes not? Maybe I'm doing something weird or wrong, what would be a better way to acheive what I want?
Code: Select all
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <atomic>
#include <WebServer.h>
std::atomic<bool> taskRun(true);
TaskHandle_t taskHandle = NULL;
WebServer webServer(80);
void setup() {
Serial.begin(115200);
delay(2000);
Serial.println("==== START ====");
WiFi.mode(WIFI_STA);
WiFi.begin("ssid", "password");
while(WiFi.status() != WL_CONNECTED);
Serial.println(WiFi.localIP().toString());
webServer.on("/reset", []() {
webServer.send(200, "text/html", "ok");
resetTask();
});
webServer.begin();
}
void loop() {
// Watch the task and start it if necessary
if (!taskHandle || eTaskGetState(taskHandle) == eDeleted) { // sometimes the task finished but is still in eReady state, so it does not restart
Serial.println(millis());
taskRun.store(true);
xTaskCreatePinnedToCore(taskFunction, "task", 10000, NULL, 1, &taskHandle, 1);
Serial.println("task created");
}
webServer.handleClient(); // allow the user to stop and restart the task through the web server
if (Serial.available()){ // allow the user to stop and restart the task through the serial monitor
Serial.read();
//delay(500);
resetTask();
//delay(500);
}
}
void resetTask() {
taskRun.store(false);
Serial.println("reset task");
}
void taskFunction(void* pvParameters) {
while(taskRun.load()) {
// do work
taskYIELD(); // give cpu time to other tasks
}
Serial.println("task finished");
vTaskDelete(NULL);
}
What is happening, why does it sometimes work and sometimes not? Maybe I'm doing something weird or wrong, what would be a better way to acheive what I want?