I am trying to test my FreeRTOS-PLUS-TCP echo server. I have a listening task and a server task. As soon as my connection gets accepted, I create the server task with xTaskCreateStatic();
This needs to stay a static allocated task. However, as I only have allocated the memory once, I need to ensure that I have only one Instance of this task running. I do this with a static variable that is reset before calling vTaskDelete(NULL). But there is still the edge case that the new task is created between resetting the variable and the actual task deletion in the idle task. Is there a solution to mitigate this issue?
Iâd avoid creating/deleting tasks dynamically (in general).
Create the server task once and keep it running.
Make âlistenâ just a state in the server task state machine. Itâs the inital state.
On accept make a state transition to âactiveâ i.e. serving. On disconnect go back to âlistenâ state.
I canât see no real need or benefit to split it into listen and server tasks
vTaskDelete(NULL) doesnât actually get processed until the Idle task gets time.
As Hartmut says, the best way to handle this condition is create the task one, best at startup, and then it waits to be notified, and then does its work, then goes back to wait again.
Note, âCreatingâ a task does nothing to initialize it again that canât be done in the task itself as part of the loop, and creating and destroying it each time is just spending CPU cycles, and introduces the race condition you note.
The way to mitigate the issue is to avoid the race between destruction and creation by not doing them.
Tasks blocked on a signal use effectively zero resources (except their memory, but being static, nothing else could use it anyway).
I was going to recommend wrapping variable reset and task deletion in a pair of functions: vTaskSuspendAll() and xTaskResumeAll(). However, the latter function canât be executed after a task is deleted itself.
If keeping task deletion/creation principle, you may clear variable and delete the task from another task. And with protection of that critical section with scheduler suspension/resume, youâll got it work regardless of efficiency.
Yes, makes sense to me. Thank for the explanation.
When would I want to support several instances, would I still stick to that solution? That would mean to create them first and notify them when needed, right?
Multiple instances could still use that method. The one case where you would want to create and destroy the tasks is if you need the memory for some other purpose which is, in my experience, relatively rare. You can make one âtaskâ do several different functions just by having the notification that it waits for tell it which operation to perform. As long as the different tasks take similar memory, changing the code path for the different operations works well.
Yes, occationally you have a problem where sometimes you need more storage for data vs a task running, and sometimes you might have one task that needs a lot of stack, instead of two tasks with smaller stacks, but those are significantly rarer cases.