Author Topic: Choosing Between Mutex, Semaphore, and Queue in RTOS  (Read 3210 times)

0 Members and 1 Guest are viewing this topic.

Offline az1

  • Regular Contributor
  • *
  • Posts: 61
  • Country: us
Re: Choosing Between Mutex, Semaphore, and Queue in RTOS
« Reply #25 on: July 14, 2026, 10:32:12 am »
I think an RTOS is the best thing since sliced bread (to use an English expression) and even in the 1980s I wrote my own (Z180,Z280) basic ones. It is just a super efficient way to do "real time" software.

The FreeRTOS mutex code is fairly convoluted. I am not sure why. One could achieve the same thing with a test/set instruction which I believe the arm32 has. The Z280 had it and the overhead is basically nothing. On others you have to disable interrupts to do the same thing.

I've avoided using queues. AFAICT FreeRTOS allocates space for these on an internal heap. This should be safe since the malloced RAM is never freed. But I've not seen a need. It is an attractive thing in terms of "architecture" but is rarely needed.

I have used FreeRTOS timers for various things. They work well.

In Rust land, I've been using Embassy which provides a few stock options for single core ARM mutexes (via embassy-sync): critical sections, checking if you're in thread mode, and no-op.  Mutexes in Rust (embedded or otherwise) wrap the variable they're protecting, to access the contents you lock the mutex and the lock is dropped when it goes out of scope.  Timers get placed in a queue and handled by a single timer peripheral.  The whole thing is refreshingly straightforward, although the time keeping doesn't lend itself well to ARM's systick peripheral. When it clicks that most of the "magic" happens at compile time and not runtime it's a bit of a eureka moment.

On 32F4, are <= 4 byte variables not atomic if not aligned? AFAIK the compiler aligns most of them anyway...

Well, what's left? 1- and 2-byte variables? Byte sized variables are inherently aligned. Unaligned 16- and 32-bit access itself is not guaranteed regardless of atomicity.  IIRC v6m doesn't allow it, and v7m (and newer) can be configured to allow it. 

The ARM v6m manual says (v7m manual contains similar verbiage):

Quote
The only ARMv6-M explicit ARM processor accesses that exhibit single-copy atomicity are: all byte transactions, all halfword transactions to 16-bit aligned locations, all word transactions to 32-bit aligned locations. … When an access is not single-copy atomic, it is executed as a sequence of smaller accesses, each of which is single-copy atomic, at least at the byte level.

Which to me means no, unaligned access is not atomic.
 

Offline Tation

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: pt
Re: Choosing Between Mutex, Semaphore, and Queue in RTOS
« Reply #26 on: July 14, 2026, 11:17:39 am »
What if, for some reason, the task emptying the queue stops sending items? Will the queue eat all RAM? AFAIK, in freeRTOS you can limit the size of a queue, but not in Zephyr (you need here a message queue instead).

For such simple application I will use a circular buffer. R and W pointers to it do not need to be protected in any way, as are not shared between tasks. The actual data need to be protected, though, but ensuring atomic access to it (if the architecture supports it) or disabling/enabling IRQ around the access is enough. No heap consumption, also (except if you insinst on malloc-ing the buffer). No need for mutex, semaphore, etc., although you may prefer to use a mutex to grant access to the data, in case disabling/enabling IRQ seems too dirty to you.

Incidentally, Zephyr uses a circular buffer on its implementation of message queues.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3519
  • Country: ca
Re: Choosing Between Mutex, Semaphore, and Queue in RTOS
« Reply #27 on: July 14, 2026, 01:03:54 pm »
Just for fun some M23 and M33 cores don't either.

Really?
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 6004
  • Country: gb
  • Doing electronics since the 1960s...
Re: Choosing Between Mutex, Semaphore, and Queue in RTOS
« Reply #28 on: July 14, 2026, 01:20:04 pm »
Quote
Unaligned 16- and 32-bit access itself is not guaranteed regardless of atomicity

On 32F4 unaligned access is supported. For CPU, not for DMA.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online uer166

  • Super Contributor
  • ***
  • Posts: 1265
  • Country: us
Re: Choosing Between Mutex, Semaphore, and Queue in RTOS
« Reply #29 on: July 14, 2026, 05:54:56 pm »
A regular old load/store is guaranteed to be atomic on 32-bit ARM when aligned such as M0/M4/M33, etc.

That holds true at the ARM machine level. However, the abstract C memory model only provides atomicity guarantees for variables qualified with _Atomic. Strictly speaking, to perform an atomic store or load while avoiding heavy hardware synchronization barriers, you had to write:

Code: [Select]
_Atomic int counter = 0;
...
atomic_store_explicit(&counter, 5, memory_order_relaxed);

Without _Atomic, the compiler would still be allowed to emit e.g. four STRB instructions for  counter = 5, which would result in byte tearing and no longer be atomic. This explicit syntax guarantees a single, undivided 32-bit STR instruction (on ARM, or whatever equivalent instruction is required for the target architecture).

While developers often assume a compiler would never split a standard 32-bit assignment, relying on this behavior makes the code compiler- and machine-dependent and non-portable. Without _Atomic, the compiler has the legal right to alter the generated instructions, forcing us to rely on implementation artifacts rather than the official language standard.

Furthermore, since lock-free atomics are not supported for every size on every CPU, one should check the capability explicitly. For several trivial types, there are ATOMIC_xxx_LOCK_FREE macros available. For more complex types, one can verify lock-free status at runtime, e.g.:

Code: [Select]
_Atomic struct MyData my_var;

if (!atomic_is_lock_free(&my_var)) {
    configASSERT(0);
}

Unfortunately, atomic_is_lock_free() is a runtime check (it is not a compile-time constant expression). While GCC and Clang enable compile-time verification via the __atomic_always_lock_free() built-in, it remains an extension and is not part of standard C.

Pedantic people love pointing out that the compiler may emit non-atomic or unaligned writes/reads here but conveniently never show actual C code or example of why/when it happens in a sane scenario.

Something like a volatile uint32_t being written/read in different contexts will not generate unaligned code unless you pack it intentionally in a struct after bytes or do something else weird. Note that you *do* have to be explicit about size, which is a good practice anyway.

Now I don't know what happens with uint8_t or uint16_t exactly, I think the situation is slightly more complex but I've never had the need to use non-word sized variables in multi-ISR or task state communications.

There is one case where I do use atomic_store_explicit() with the correct memory model though: a FIFO single header set of functions that I may want to reuse in OoO cores that may actually shuffle the write order. In that particular case a lot of simplified assumptions don't hold true anymore necessarily, though again I haven't worked with bigger stuff that closely, only Cortex-M4/M33/M0
 
The following users thanked this post: voltsandjolts

Online uer166

  • Super Contributor
  • ***
  • Posts: 1265
  • Country: us
Re: Choosing Between Mutex, Semaphore, and Queue in RTOS
« Reply #30 on: July 14, 2026, 05:58:05 pm »
relying on this behavior makes the code compiler- and machine-dependent and non-portable.

This specifically pisses me off in professional settings. You know what else is machine-dependent and non-portable? Bare metal or FreeRTOS code interacting with peripherals on a STM32  :horse:
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 6004
  • Country: gb
  • Doing electronics since the 1960s...
Re: Choosing Between Mutex, Semaphore, and Queue in RTOS
« Reply #31 on: July 14, 2026, 06:36:36 pm »
Hardware access will never be portable. No shit Sherlock, as they say here :)
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline az1

  • Regular Contributor
  • *
  • Posts: 61
  • Country: us
Re: Choosing Between Mutex, Semaphore, and Queue in RTOS
« Reply #32 on: July 14, 2026, 08:43:35 pm »
Just for fun some M23 and M33 cores don't either.

Really?

https://community.nxp.com/t5/S32K/Understanding-Atomics-i-e-STREX-LDREX-on-S32K3/m-p/2356618?profile.language=en

https://www.renesas.com/en/document/tcu/add-restriction-exclusive-access?r=1054141

Quote
Unaligned 16- and 32-bit access itself is not guaranteed regardless of atomicity

On 32F4 unaligned access is supported. For CPU, not for DMA.

CCR.UNALIGN_TRP configures whether to always fault on unaligned access, however ldrex/strex will always fault on unaligned access.
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 6004
  • Country: gb
  • Doing electronics since the 1960s...
Re: Choosing Between Mutex, Semaphore, and Queue in RTOS
« Reply #33 on: July 14, 2026, 09:11:56 pm »
What is the power-up state of that bit? I am having some trouble finding that.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3519
  • Country: ca
Re: Choosing Between Mutex, Semaphore, and Queue in RTOS
« Reply #34 on: July 14, 2026, 09:21:11 pm »
Just for fun some M23 and M33 cores don't either.

Really?

https://community.nxp.com/t5/S32K/Understanding-Atomics-i-e-STREX-LDREX-on-S32K3/m-p/2356618?profile.language=en

https://www.renesas.com/en/document/tcu/add-restriction-exclusive-access?r=1054141


These are errata.

In the Renesas case, LDREX/STREX are there, but Reneses implemented the AHB interface incorrectly, so the instructions don't work as expected.

In the NXP case they do actually work, but only within the core.
 

Offline az1

  • Regular Contributor
  • *
  • Posts: 61
  • Country: us
Re: Choosing Between Mutex, Semaphore, and Queue in RTOS
« Reply #35 on: July 15, 2026, 02:52:25 am »
Just for fun some M23 and M33 cores don't either.

Really?

https://community.nxp.com/t5/S32K/Understanding-Atomics-i-e-STREX-LDREX-on-S32K3/m-p/2356618?profile.language=en

https://www.renesas.com/en/document/tcu/add-restriction-exclusive-access?r=1054141


These are errata.

In the Renesas case, LDREX/STREX are there, but Reneses implemented the AHB interface incorrectly, so the instructions don't work as expected.

In the NXP case they do actually work, but only within the core.

Errata?  Semantics.  Yes, ldrex/strex are part of the armv7/8m spec.  Unfortunately you're still going to find non-conforming MCUs out in the wild.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf