Setting a task handle to NULL before it is deleted

chalamel wrote on Sunday, April 29, 2018:

Hello. I am curious about the safety of an operation i’m doing. I have two tasks A and B. Task A spawns task B and later deletes it by posting a notification to the task. It is done this way and not directly with vTaskDelete(taskBHandle) as task B should finish the work it is doing before being deleted. I want to make sure two instances of task B can never be running at once, and so I check whether taskBHandle is NULL before creating the task. It goes like this:

Task A, on deleting task B:

if(taskBHandle != NULL) {
xTaskNotifyGive(taskBHandle);
taskBHandle = NULL;
}

TaskB:
if( ulTaskNotifyTake(pdTRUE, 0) > 0) {
vTaskDelete(NULL);
}

This seems to work just fine, but is it safe? B’s task handle is NULL when it deletes itself. Does task B hold a copy of this handle or could this cause issues?

rtel wrote on Sunday, April 29, 2018:

I presume taskBHandle is a variable that was set when you created the
task. As such, it is just a copy of the handle, not really the handle.
Handles are in fact opaque pointers to the task’s TCB, so deleting the
pointer to the TCB does not delete the TCB.

You need to be careful of race conditions here though. If the task
being deleted is guaranteed to be deleted before taskBHandle is set to
NULL then it must have a higher priority than TaskA, and be waiting on
the notification rather than waiting on any other object.

Also, if a task deletes itself, then the memory it occupied won’t
actually get deleted until the idle task runs and cleans it up (that is
how all tasks used to be deleted until recent versions, so may apply to
all tasks depending on the FreeRTOS version you are using).

You could potentially define the portCLEAN_UP_TCB(xHandle) macro (see
where it is called from in tasks.c) to know when the task is actually
gone - you would have to compare xHandle against taskBHandle to know it
was the same task - but even then the macro is called immediately before
the memory is freed - another task will not run until that has happened
but don’t reuse the handle inside portCLEAN_UP_TCB() itself. This is
getting into ‘expert user’ territory.

Alternatively, if this is the only task that is being created and
deleted in your system, you could uxTaskGetNumberOfTasks() to see how
many tasks there are - it will go up by one when you create the task and
down by one when you delete it again.

chalamel wrote on Wednesday, May 02, 2018:

I figured I could run into race conditions like that. I’l see if I can find a cleaner way to do this.

Thanks for the swift reply!