After I entered the critical , I created a new task, but the critical did not exit. Should my new task run? This new task has the same priority as my current task. Thks.
What do you mean by “but the critical did not exit”.
Critical sections only end when you call the taskEXIT_CRITICAL() function.
While in a critical section, the scheduler will not switch to a new task (at least if you follow the rules)
Note the line from taskENTER_CRITICAL:
FreeRTOS API functions must not be called from within a critical section.
So, creating a task inside one (which requires calling a FreeRTOS API) isn’t a defined operation.
I will also note that creating a task is probably a bigger operation than what I would do under a critical section (if it was allowed), but maybe your interrupt requirements aren’t very strict.
Also,
As @richard-damon pointed out, could you share a code snippet of your code so that it is clear what your problem is?
@richard-damon @ydhuang
Hello , This is my code , thanks!
void Task1(void *parameter)
{
taskENTER_CRITICAL();
xTaskCreate(Task2);
taskEXIT_CRITICAL();
printf("This is Task 1\r\n");
for(;;)
{
vTaskDelay(10);
}
}
void Task2(void *parameter)
{
printf("This is Task 2\r\n");
for(;;)
{
vTaskDelay(10);
}
}
The result is that the “This is Task 2” is printed first and the “This is Task 1” is printed later
Hi @passerby,
From your code snippet, task1 has exited the critical section before calling printf
. So that gives scheduler chance to do context switch from task1 to task2.
And you might be interested in the reason of preemption of same priority. Refer to configUSE_PREEMPTION and configUSE_TIME_SLICING, scheduler does context switch for same priority task when these two configurations are enabled.
Thanks.
Hi , @ActoryOu :
If task1 changes as follows
void Task1(void *parameter)
{
taskENTER_CRITICAL();
xTaskCreate(Task2);
printf("This is Task 1\r\n");
taskEXIT_CRITICAL();
for(;;)
{
vTaskDelay(10);
}
}
The results are still the same, “This is Task 2” is printed first and the “This is Task 1” is printed later. Is this normal?
Thanks.
Hi,
I’ve tried windows simulator and it works as expection.
Could you help to provide more info of your environment? (platform, FreeRTOS version, FreeRTOSConfig.h)
output from WinSim:
vTaskStartScheduler
This is Task 1
This is Task 2
Thanks.
Hi @ActoryOu :
My platform is ZYNQ7000 , Version is V10.0.0 , configUSE_PREEMPTION 1
configUSE_TIME_SLICING 1.
I use time slice scheduling , the phenomenon I’m looking for is to print Task1 first. So I’m confused. Are there any possible reasons for this error phenomenon
Thanks.
As I mentioned at the beginning, your code is invalid, and no behavior promised, as you are calling an API function inside a critical section. This is just not allowed.
Perhaps you should just suspend the scheduler, then create the task. You still might not be able to call prints, as it might block on the I/O and you aren’t allowed to do that with the scheduler suspended.
The big question perhaps is what are you actually trying to do, i.e.what is the real problem to solve, since your current attempted solution path is just broken,
Hi @richard-damon :
I can also to change a way to solve this prolem . It’s just that the phenomenon is puzzling , My understanding of the critical is that it will stop scheduling.
Thank you for your help @richard-damon @ActoryOu @ydhuang .
Thanks.
The critical section is used to make any application code inside the section run without being interrupted (it disables interrupts). Yes, it does suspend the scheduler but that is not its purpose. Like @richard-damon says, calling FreeRTOS API functions within a critical section is undefined behavior, so you should not expect the xTaskCreate()
call within the critical section to do what you expect it to do. If you just want to suspend the scheduler, maybe vTaskSuspendAll()
and vTaskResumeAll()
would be a better choice?
As others mentioned, you may be falling victim to an unordered sequence of I/O calls. printf() is not reliable. Instead of it, use something like (Pseudo code)
unsigned char g_Events[10];
unsigned long g_EventCounter;
task1:
…
g_Events[g_EventCounter++]=‘1’;
…
task2:
…
g_Events[g_EventCounter++]=‘2’;
…
then evaluate the array posthumously.
Depending on the exact port, critical sections might NOT stop the scheduler, that only happens for ports that you an interrupt that gets masked by the critical section to invoke the schedulers. Other ports use a synchronous trap or a direct call which is NOT blocked by the critical section. A scheduling event won’t happen on its own on those, because no interrupt that could cause such a request can happen, but calling an API function still might cause one.
Basically, breaking the rules should only be done if you know what you are doing, and know things will behave the way you want (and keep up on possible changes to that behavior with updates).
Thanks! Help me a lot!