Problem with deleting tasks using vTaskDelete();

Hello, I’m new in this comunity, so sorry for all mistakes (also language cause english it’s not my main language). I’m using ESP32.

I would like delete task using vTaskDelete(), but situation is:

  1. My task run +/- 15 times - function eTaskGetState() returned value ‘2’
  2. Next time task will suspended - function eTaskGetState() returned value ‘4’
  3. I’m trying delete task if state = 4 and run it again but it isn’t working

This is my code: (I can’t put in all)

xTaskCreatePinnedToCore(turnOn_function, "turnOn_task", 10000, (void*)&currentmess, 1, &turnOn_task, 1);
        if(eTaskGetState(turnOn_task) == 4)
          Serial.print("STAN TURN_ON : ");
          if(turnOn_task != NULL)
            Serial.print("USUNIETO TURN_ON : ");
          xTaskCreatePinnedToCore(turnOn_function, "turnOn_task", 10000, (void*)&currentmess, 1, &turnOn_task, 1);

        Serial.print("WYKONANIE TURN_ON : ");

I will be really grateful for help :slight_smile:

What exactly is not working ?

One big issue that I see is once you call vTaskDelete(turnOn_task) you should not then use turnOn_task until you create the new task and put it into that variable. The call to eTaskGetState(turnOn_task) after the call to vTaskDelete is accessing freed memory, so is invalid.

If when it suspends itself you are just going to create it again, why not have it just in its own code go back to its beginning and wait for a new request?

After +/- 15 times task become suspended and I can’t run it again.

On serial port monitor:

[0] get Text: #00ffff

And next loop not working:

STAN TURN_ON : 4 // checking state before delete
USUNIETO TURN_ON : 4 // after delete
WYKONANIE TURN_ON : 4 // after run again

So how to check if the task is running at the moment?

It is tricky to find out if a handle you have still is connected to a active task. If you have given the task a unique name, you could enable the lookup task by name function and see if you can find it, or run a call to get the status of all tasks and see if it is listed.

Basically, in C you need to keep track of the lifetime of things allocated dynamically, like you are doing with tasks. Unless you code KNOWS the handle to still be valid, it shouldn’t be using it. Here it actually should know that it wasn’t (maybe you should have set the handle to NULL right after the call to delete, and you code should be checking if it is NULL before using it.

Something like this?

turnOn_task = NULL;

if(turnOn_task ==NULL)
xTaskCreatePinnedToCore(turnOn_function, “turnOn_task”, 10000, (void*)&currentmess, 1, &turnOn_task, 1);

I would NULL out the task handle before the delay, but otherwise yes, but it multiple tasks are using that handle you will need to put some sort of guards around it usage.

Ok, and can You tell me if eTaskGetState return value f.e. ‘0’ it is ‘Running’? And ‘1’ is ‘Ready’? etc. Because in documentation is ‘pdRunning’ but in my project this function return values.

eTaskGetState returns an enum as documented here. I’d propose to use them instead of literal values.
If you can ensure that the turnOn_task variable is not used elsewhere, you could delete the (self ?) suspended task and just create a new instance. Even if the final cleanup of the associated resources is a bit delayed. Given that you’re not short of RAM you don’t have to wait.
On the other hand waiting for a task being suspended to delete and immediately re-create it seems to be a sub-optimal solution.
As Richard proposed why not letting it run and signal the task to re-do its job by a task notification or queue ?

You really should be comparing them to the enum values in task.h.

eRunning(=0) will be returned for the currently running task, which will be the task making the request.

eReady(=1) will be returned if the task is ready to run, and will run when it becomes the highest priority task

eBlocked(=2) will be returned if the task has blocked on some primitive, (or executed a delay). It will wake up when that time has expired, or if blocking on a primitive that primitive is now available.

eSuspended(=3) will be returned if the task has been suspended or blocked for an indefinite period of time.

eDeleted (=4) will be returned if the task has been deleted but the final cleanup of resources has not yet occurred.

eInvalid(=5) will be returned for some error conditions.

Note that eDeleted might get returned if the resources HAVE been cleaned up, and thus the handle is no longer valid, if the contents of the TCB block still look enough like a TCB so that eTaskGetState thinks it is ok (it doesn’t do a lot of testing, so this is possible). The eDeleted case is mostly for the case of the call to get the state of all current tasks, so those waiting to be cleaned up have a status to give them. Maybe as part of cleanup, just before freeing the memory it should have been changed to eInvalid (after unchaining from the lists) so that later usages of the deleted memory indicate this.

Note, I am looking at a current version of FreeRTOS for the values of these states, I don’t know if they have changed over the versions, or if the ESP modification made changes to them.

With this set of values, 4 indicated it was already schedule to be deleted, so deleting again could well corrupt things.

I think the eDeleted case can be useful when statically creating tasks with provided TCB/stack memory to know when it’s save to re-use the supplied memory.
But I’ve to admit I didn’t check the sources so I’m guessing and I don’t delete tasks either.

I’m really fresh in RTOS, so please forgive me my stupidity…
So, it does mean I can run second this same task when first task is running yet? It’s OK? Because I exacly think about this. But I don’t sure it is correct.

I think, in this case, program ran task ‘turnOn_task’ too many times in the same moment and doesn’t deleted them (
which should be deleted), what makes fail. It’s possible?

A given function can be used by many tasks if you want as the function to run, that is one reason you can give it a parameter. Also, most tasks that I use have a big loop in them so when they finish one request given to them, the wait for another request in some way (semaphore given, item in queue, direct-to-task notification given, etc).

Actually, I execute:

Serial.println(“BEFORE turnOn”);
xTaskCreatePinnedToCore(turnOn_function, “turnOn_task”, 10000, (void*)&currentmess, 1, &turnOn_task, 1);
Serial.println(“New task turnOn should start”

This working +/- 10 times,
And I see in serial monitor both Serial.println, but for next times function doesn’t start. So this code is execute, without effects. Why? :confused:

I checked a few things.

The state in function is 0 = running, and after state is 2 = ‘blocked’ it is a true, because checking state is after 500 miliseconds and function is beeing done about 1 second so probably when the state is checking in function is delay.
But after 15 times executing this functions state inside isn’t checking so function doesn’t turn on. And state after command xTaskCreate…() is 4 (suspended). And again my question… why? In end of function is ‘vTaskDelete(NULL)’ of course. Stock is overflow?

EDIT: I increased stack from 1000 to 3000 and it worked +/- 40 times. But my webserver got failed and broke down connection

If 4 is suspended, then you are running a modified version of the software, as in mine, 3 is suspended and 4 is deleted. (But then xTaskCreatePinnedToCore isn’t standard either).
I note that you are not checking for errors in the task creation, it could be that some resource has gotten exhausted.

I’m confused. If you need control about lifetime of turnOn_task you should create and delete it in your main task and let turnOn_task halt in suspended state. The turnOn_task should not self-delete because you lose control about it.