richard_damon wrote on Wednesday, February 21, 2018:
If these are functions called by a Pend from ISR call, then they will run from a common task (the Timer/Service Task) and thus will properly interlock with each other, the problem being that they don’t have the right signature for those. If you have some other singular button task that processes all buttons and calls these as appropriate, then again, you have an external interlock to avoid the race condition in the functions.
Without something like this, you code has a race condition in that you check that the handles are null, and then create a task, and AFTER that task is created you set the handles so the other routine won’t run. It is possible for an event to happen between those two points, ‘racing’ the code to disable the creation of the second task, and cause a malfunction.
I use two different options, depending on the exact need, to handle such a case,
The first, rather than check the two task handles, I would create a flag variable to indicate if one of the tasks is running, Then inside the routine, I would check the flag, and if clear set it then create the task. The big difference from your code, is that the test and set would be done inside a critical section preventing the race condition, something like
taskENTER_CRITICAL();
if(flag == 0) {
flag = 1;
taskEXIT_CRITICAL();
.. create the task ..
} else {
taskEXIT_CRITICAL()l
}
When the task is done, it can set the flag back to 0.
The second method would be to use a semaphore as the guard, and the check would attempt to take the semaphore (possibly with a zero timeout for your case) and if it got it, it would create the task. The task when done would give the semaphore back to let the next activation happen.
The first is simpler in the case where you know you will always want to totally ignore the second request. The second allows for including a short delay to aquire the semaphore, so a request to start task2 just as task1 is finishing up might succeed.