How to choose a critical section protecton approach? taskENTER_CRITICAL or vTaskSuspendAll or mutex?

The first question is how to choose between taskENTER_CRITICAL and vTaskSuspendAll?
I have read the manual and found that taskENTER_CRITICAL will disable interrupt while vTaskSuspendAll won’t disable interrupt but only suspend the scheduler. However, I still cannot understand the rational behind API xQueueGenericSend. In xQueueGenericSend, the code1 between line 761 and line 897 uses taskENTER_CRITICAL to protect itself, while the code2 between line 902 and line 941 uses vTaskSuspendAll to protect itself. What is the rational behind the protection approach chosen between the code1 and the code2?

The second question is how to choose between taskENTER_CRITICAL and mutex?
In this post, it said, "You should not be using taskENTER_CRITICAL to protect something that can take 6ms, let alone 80ms. A mutex is a much better option here, as that will only block the other tasks that try to use the file system. " As regarding to my platform, it is ARM Cotext-M4 processor running at 168 MHz and has a time slice as 1 ms. So, if the critical section lasts longer than 6*time slice, this is unacceptable. I think a reasonable critical section should last shorter than 1/n * time slice. So the rational behind how to choose between taskENTER_CRITICAL and mutex maybe that

  • If the critical section lasts shorter than 1/n * time slice then taskENTER_CRITICAL can be used.
  • If the critical section lasts longer than 1/n * time slice then mutex should be used.

Is what I am understood correct? If so, then which n should be chosen in practice?

Thanks in advance!

First when referring to line numbers of code you need to add the actual (FreeRTOS) version of that code :wink: But I can’t say much about the implementation of xQueueGenericSend anyway.
The concept of critical sections was recently very well explained by Richard Damon here in the forum.
When using critical sections you must be aware that it affects your (worst case) interrupt response time. That means an ISR of a hardware interrupt might get delayed because all interrupts are disabled while executing code inside a critical section.
That’s the benefit of just suspending all tasks. Interrupts remain enabled and get handled by their corresponding ISRs.
There is no common rule how long ‘very short’ is. It depends on the (real-time) requirements of your application.
Both protection methods are very light weight and fast, but affect the whole application i.e. all tasks regardless of their priorities.
In general you should narrow down the scope of any protection as much as possible. So when protecting the access to some data used by only 3 tasks out of 5 in your application, it’s almost always better to use a mutex used by these 3 tasks and all other tasks are not affected.
Also mutexes take the task priorities into account to decide which of the maybe blocked other tasks get’s the mutex next when it gets released by the task currently holding it.

1 Like

The basic characteristics that are used to determine between critical sections, suspending the scheduler and using a mutex are that critical sections are fast and cheap to perform, but have a wide impact as they disable interrupts. Critical sections affect interrupt latency, so I believe that one rule that FreeRTOS uses internally is that a critical section needs to have a strictly bounded execution time, and that time should be fairly short. I user code, since you know more about the requirements you may be able to relax some of these, but that is a good baseline. I personally limit critical sections to things that can be measured in small number of microseconds at most.

The distinction between stopping the scheduler and a mutex is perhas a bit more nuanced. Suspending the scheduler has wider impact, as it affects ALL tasks, and inside the section you can’t do anything that might block. It requires no ‘setup’ to create the locking agent like a mutex would. It doesn’t protect against ISR access (which is why when you suspend the schedule it sets a flag to tell the ISRs not to modify the main task lists). The disadvantage of suspending the scheduler is that it takes some time (vs just a couple of instructions for a critical section). FreeRTOS uses suspending the scheduler if the time period isn’t both strictly bounded and short.

A Mutex on the other hand only interacts with other tasks that use the same mutex, so has the least impact on the full system. I don’t think FreeRTOS uses muteness internally in the core, in part to avoid making them mandatory in a minimum configuration.

1 Like