I have one question regarding the task creation procedure.
I’ve noticed that xTaskCreate() sometimes never returns on FreeRTOS windows port(MinGW).
I am not sure whether my usage for xTaskCreate() is correct. Could you give me advice or your opinion?
[Procedure]
Create one task(task0).
Start the task scheduler.
Create multiple tasks(task1 to taskN) in task0.
The last task(taskN) has higher priority than other tasks(including the caller(task0)).
[Result]
xTaskCreate() sometimes does not return to the caller(task0).
The debugger shows that the program is stuck in ReleaseMutex() in
PortGenerateSimulatedInterrupt() in prvAddNewTaskToReadyList() in xTaskCreate().
[Frequency]
Frequency of this trouble depends on the number of tasks.
When N is greater than 200, the issue occurs around 50% of the time.
When N is small (e.g., 10), the issue is rare but still occurs occasionally.
[Platform]
I run same program on FreeRTOS windows port and AArch64 port.
This behavior is not observed on FreeRTOS AArch64 port.
[Environment]
I have downloaded the latest FreeRTOS from Github.
FreeRTOS:V11.1.0
Compiler:MinGW-w64 v13.2.0
IDE:Eclipse v2023-12
OS:Windows 11
[Code]
The following code was added to the FreeRTOS MinGW demo appilication.
#define NUMBER_OF_TASKS 200
#define HIGHER_PRIORITY (configMAX_PRIORITIES - 1)
#define LOWER_PRIORITY (configMAX_PRIORITIES - 2)
void task0( void * pvParameters );
void task1( void * pvParameters );
void main_full(void)
{
printf( "Test is started.\r\n" );
/* create first task */
xTaskCreate( task0, "Test", configMINIMAL_STACK_SIZE, NULL, LOWER_PRIORITY, NULL );
/* Start the scheduler. */
vTaskStartScheduler();
}
void task0( void * pvParameters )
{
printf( "Task0 is started.\r\n" );
for (int i = 0; i < NUMBER_OF_TASKS; i++)
{
/* The last task has the higher priority than other tasks. */
int priority = (i == NUMBER_OF_TASKS-1) ? HIGHER_PRIORITY : LOWER_PRIORITY;
xTaskCreate( task1, "Test", configMINIMAL_STACK_SIZE, NULL, priority, NULL );
}
printf( "All tasks has been created.\r\n");
while(1)
{
vTaskSuspend(NULL);
}
}
void task1( void * pvParameters )
{
while(1)
{
vTaskSuspend(NULL);
}
}
Any advice or insight into this behavior would be greatly appreciated.
Thank you!
In the FreeRTOS Windows (Win32) simulator port, critical sections and scheduler protection are implemented using Windows Mutex (a Windows synchronization primitive), instead of disabling and enabling hardware interrupts (as is done on real embedded platforms).
Each call to xTaskCreate()uses this Windows Mutex/ReleaseMutex pair to protect the scheduler’s ready‐list. But, if you create a higher‑priority task while still holding that mutex, the scheduler immediately switches to the new task. This leaves the mutex locked in xTaskCreate(). When the new task invokes any kernel call (even vTaskSuspend(NULL)), it deadlocks trying to reacquire the same mutex.
This is why creating many tasks, with the last one at highest priority, can cause deadlock about half the times, as the preemption happens before the mutex is released.
To avoid this, you can either bulk‑create tasks at the same priority and then elevate one with vTaskPrioritySet(), or (as shown below) simply bracket your creation loop within a critical section using vTaskSuspendAll()/vTaskResumeAll() so no context switch (and thus no premature mutex contention) can occur until all tasks are safely created.
void task0( void * pvParameters )
{
vTaskSuspendAll();
for(int i = 0; i < NUMBER_OF_TASKS; i++)
{
int priority = (i == NUMBER_OF_TASKS-1) ? HIGHER_PRIORITY : LOWER_PRIORITY;
xTaskCreate(task1, "T1", configMINIMAL_STACK_SIZE, NULL, priority, NULL);
}
xTaskResumeAll();
/* Now the highest‑priority task can run */
vTaskSuspend(NULL);
}
Thank you for your kind explanation!
I tried your solution ( vTaskSuspendAll() /vTaskResumeAll()) and it solved my problem!
I have one more question about it.
I understand such limitation is only in windows port not in other real embedded platforms. Is it correct?
I tried to run same program on windows port and embedded platform. But now I plan to customize program only on windows port.
The issue stems from the Windows port implementation. In this port, FreeRTOS tasks are implemented as Windows threads, which are suspended and resumed for scheduling. A deadlock occurs when a thread is suspended while holding operating system locks during startup. As confirmed by others, this behavior is specific to the Windows port.
Thank you for quick responses!
I understand this issue is only on Windows port.
Windows port is different with real embedded platform in several cases such as performance but it is still amazing because I can check my program before preparing real device! It is wonderful experience for me!
Thanks again!