A few beginner questions on task scheduling

There are two questions confusing me:

  • If there are two tasks with the same priority, the scheduler will run them concurrently in the unit of RTOS tick. Now, task A is blocked by xSemaphoreTake() and task B calls xSemaphoreGive(), in this situation, scheduler will swap them immediately or run task B until its RTOS tick expire?

  • When will the memory coalescence algorithm be executed in heap_4? in the idle task? after each memory free? or be executed periodically in the background?

Thanks,
Evan

Two tasks can’t run ‘concurrently’ on most processors that FreeRTOS runs on, as they are single core, so can only execute a single thing at a time. Two tasks of the same priority will be automatically swapped between on every tick, if both are ready (and preemption is enabled). If one blocks, the system goes to the highest ready task, which would be that other task if it was also ready.

My understanding is that if you unblock a HIGHER priority task, then you switch to it, but if you unblock a same priority task, you won’t switch to it until the next tick (or if you block).

heap_4 will coalescence adjacent blocks when they are freed, the free function will see if the block before or after was also free, and combine them if so. The only thing that is delayed is if a task deletes itself, then some of the cleanup is postponed to the idle task, because the task can’t do all the steps to delete itself once it starts (since it isn’t around to run that code).

Yes, that’s what i meant, so i used ‘concurrently’ instead of ‘parallel’. Maybe it’s not accurate, thank for pointing out.

Oh, I got it. If so, I do a comprehensive finishing of task switching:

  • If I unblock a HIGHER priority task, then a lower priority task would be preempted, it switches to a higher priority task immediately.
  • If I unblock a SAME priority task, preemption would not happen, so it will run until next tick.
  • Regardless of priority of tasks, scheduler will switch to another highest unblock task immediately if the running task is blocked.

Do you mean it will run coalescence algorithm when I free the memory every time?
I was thinking if this would affect system performance.

Thanks a lot,
Evan

Yes, the coalescence of adjacent blocks is run every time you free a block. In order to support the coalescence of blocks, the free list is kept in sorted order, so when you free a block the list is scanned to find its place, and checked if it is adjacent to either the preceding or the following block, and coalesced as needed. This does have overhead but is the cost of undoing the fragmentation of the heap. To postpone this action would require a LOT more work to be performed, as it would basically require sorting the entire free list, it would delay the availability of the coalesced block, and perhaps most importantly would either require the malloc handler to define a new task or the current idle task would need to know details of the memory allocation handler, or at least have a special hook for it.

SInce most really real-time system don’t depend on dynamic allocation during operation but only possibly during setup, this is normally not a heavy cost. The problem with doing dynamic allocations in the midst of real-time operation is the difficulty of ‘proving’ that the allocation will succeed, and the handling of the error if it doesn’t.

Thanks for your detailed explanation :slight_smile:

Best Regards,
Evan

The tutorial guide (OK, date 2016) says that you only get this round-robin behaviour if time slicing is enabled (configUSE_TIME_SLICING set to 1) - and indicates that preemption has nothing to do with it, I think

Time slicing requires pre-emption. I mention pre-emption because I find some people will turn it off to make things ‘simpler’ (less need for critical sections) but then forget that doing that also causes other issues with other tasks not getting time. Few people turn off time slicing and then expect the system to do round robin scheduling.

I see what you mean (tasks.c:2703 in 10.0.1). I think I’d have challenged that if I’d been on the design team, but it is what it is. Doesn’t affect my use of FreeRTOS - for which many thanks! because I have preemption on and timeslicing off, to match Ada semantics.

It would be hard to argue that it is surprising that turning time slicing off disables round robin by time, since that is basically the definition of the switch.

With preemption turned off, time slicing can’t switch tasks at the tick, because that would be a preemption.