Mutex and Semaphore Train Analogy

I am trying to understand the concepts of mutex and semaphore in FreeRTOS, and I came across a train station analogy. I’d like to share my understanding and request clarification. In the mutex example, it’s like a single-track train station with a traffic light at the entrance. If the light is red, only one train can enter. When it turns green, the track is free for another train. For the semaphore, it seems to be similar but with multiple tracks, and the semaphore value determines how many trains can enter simultaneously. The semaphore value sets the limit on how many trains can be on the tracks at the same time. If the semaphore is green (value > 0), trains can enter. As trains use the tracks, the semaphore value decreases, and when it hits zero, new trains need to wait until a track becomes available. Am I on the right track with these explanations? Could someone provide a bit more i clarify the differences between mutex and semaphore in the context of FreeRTOS?

The main difference is their semantics which not only applies to FreeRTOS. It’s a synchronization primitive common to (priority based) multitasking OSs.
A mutex (mutex comes from mutual exclusion) is used to protect something as you properly described with your train station example. A semaphore is used to signal something/events.
In addition a mutex supports priority inheritance which is necessary for priority based multitasking OS to avoid an effect called priority inversion. These are common terms and there is a lot of explanations in the net if you’re interested in details.
Technically a mutex implementation can be seen as binary semaphore initialized to signaled state (so that the 1st train can immediately enter the track) with the additional priority inheritance feature which is a bit simplified in FreeRTOS because a fully fledged implementation is more complicated and would require more code and memory.

I understand that a mutex allows only one task to access a resource at a time. However, I’m having difficulty grasping how semaphores permit multiple tasks, up to a certain limit, to access a shared resource simultaneously

I miss the concept Counting Semaphore in the above discussion.

Suppose, in a network driver, there is a limited number of DMA descriptors for transmission, say 4 descriptors.

A counting semaphore can be programmed with the maximum value 4. Then for 4 times, a DMA descriptor can be obtained without waiting. The 5th requestor will have to wait for an available descriptor.

The credit mechanism using a counting semaphore is also a very good use case in addition to signaling a number of events (like interrupts from an ISR to a task or something) :+1:

also, it is imprtant to point out that muteces trace ownership - which is a requirement for priority inheritance but also unveils the nature of a mutex. The OS knows which task has claimed the mutex (the current “owner”). It is mandatory that only the owner releases the mutex. Any code using muteces uses the sequence

[claim mutex]
[ access protected ressource]
[release mutex]

Any other usage of a mutex is an error.

Semaphores a different; binary semaphores can be used similar to muteces, but the OS will not track ownership as a semaphore is not being "owned - " a typical usage of a semaphore would be for one task to signal availability of data to one or more other threads.

Unfortunately, the naming of the synchronization objects amplifies the confusion. Semaphores were the first constructs to enter the world of synchronization in concurrent programming, and the name is still used as the jolly joker for all kinds of synchronization techniques, although in 90% of everything referred to as “semaphores,” the use case is really muteces.