Why were semaphores developed in RTOS

Thread Starter

MTech1

Joined Feb 15, 2023
181
Hello,
I’m trying to understand semaphores in RTOS. From what I know, a task can be in three states ready, running, or blocked. I’ve also read that semaphores are used as a signaling mechanism to share resources.

But I’m still confused about one thing: why were semaphores originally developed? What specific problem were they meant to solve?

For example, suppose we have two tasks with the same priority, and both of them want to access the same resource (say a shared peripheral). I think Without some kind of control, both tasks might try to use it at the same time and cause conflicts. I’ve heard that semaphores help in this situation, but I don’t fully get it
 

nsaspook

Joined Aug 27, 2009
16,249
The best way to understand why is by doing.

You drive a car? What problem are signal lights and stop signs trying to solve?

Mutexes are for mutual exclusion (one at a time), while semaphores are for managing a pool of resources or signaling events.
 
Last edited:

BobTPH

Joined Jun 5, 2013
11,463
Hello,
I’m trying to understand semaphores in RTOS. From what I know, a task can be in three states ready, running, or blocked. I’ve also read that semaphores are used as a signaling mechanism to share resources.

But I’m still confused about one thing: why were semaphores originally developed? What specific problem were they meant to solve?

For example, suppose we have two tasks with the same priority, and both of them want to access the same resource (say a shared peripheral). I think Without some kind of control, both tasks might try to use it at the same time and cause conflicts. I’ve heard that semaphores help in this situation, but I don’t fully get it
Quite simple really.

Before using the service you must request the semaphore. If it is busy, you will block. When you continue, you can use the resource, and everyone else requesting it is blocked. When you finish and release the semaphore, someone else can use it.
 

MrChips

Joined Oct 2, 2009
34,625
Semaphore is another name for flag, It is essential in logic and was developed from day one of digital logic, long before RTOS came along.

A semaphore is an indicator or reminder that something special has occurred. As simple examples, you can use a flag to indicate that an overflow occurred, or that a value is negative. A flag is used to indicate that a keyboard button was pressed or a hardware device is ready. In hardware, it might be implemented as a flip-flop, while in software it is implemented as a bit in a register or memory word.
 

nsaspook

Joined Aug 27, 2009
16,249
A common use of a mutex using a semaphore (hardware or software) is the atomic updates of multi byte variables in a 8-bit controller. A 32-bit value is being shared between a I/O ISR and the main program processing loop. To stop multi byte variable corruption, a flag (non-atomic update in progress) could be set to allow only one to write complete 32-bit value updates or you could set a flag (register bit) to stop ISR interrupt task updates when the main task is modifying/reading the 32-bit value.

Either way works but usually the interrupt disable is more efficient if the hardware allows for buffering I/O for short periods of time with a FIFO or similar mechanism instead of polling a wait flag (in the RTOS kernel or main process) for access to non-atomic updated variables.
 
Last edited:

BobTPH

Joined Jun 5, 2013
11,463
Semaphore is another name for flag, It is essential in logic and was developed from day one of digital logic, long before RTOS came along.
This is a different meaning than the software / multitasking meaning. Semaphore in this context is the same as a mutex.

Its implementation is a lot more complicated than a just a binary flag, and is typically done with an atomic read / write operation on sophisticated processors. On single-processor micros, it is often implemented by turning off interrupts, then checking and updating a memory location.
 

nsaspook

Joined Aug 27, 2009
16,249
For Linux and most other RTOS type systems where multi-task access to 'something' is needed. One reason not to use a RTOS unless it's really necessary. The issues with 'real' multi-tasking processing are not trivial.

Inside my Linux (4 core Orange Pi box) daq_bmc driver that talks my Q84 board firmware.

Make sure my packet is not molested by another process.
C:
struct mutex drvdata_lock, cmd_lock;

    mutex_lock(&devpriv->drvdata_lock);
    chan = devpriv->ao_chan & board->n_aochan_mask;
    range = devpriv->ao_range;

    /* use single transfer for all bytes of the complete SPI transaction */
    packet->bmc_byte_t[BMC_CMD] = CMD_DAC_GO;
    packet->bmc_byte_t[BMC_D0] = (uint8_t) (value & 0xff);
    packet->bmc_byte_t[BMC_D1] = (uint8_t) ((value >> 8)&0xff);
    packet->bmc_byte_t[BMC_D2] = (uint8_t) (value & 0xff);
    packet->bmc_byte_t[BMC_D3] = BMC_D3;
    packet->bmc_byte_t[BMC_D4] = BMC_D4;
    packet->bmc_byte_t[BMC_EXT] = (uint8_t) range;
    packet->bmc_byte_t[BMC_CKSUM] = CHECKBYTE;
    packet->bmc_byte_t[BMC_DUMMY] = CHECKBYTE;
    bmc_spi_exchange(dev, packet);

    s->readback[chan] = value;
    devpriv->ao_count++;
    mutex_unlock(&devpriv->drvdata_lock);
    smp_mb__after_atomic();
Make sure the current command sequence is not molested by another process.
C:
/*
 * Talk to the ADC via the SPI Q84
 */
static int32_t daqbmc_ai_rinsn(struct comedi_device *dev,
    struct comedi_subdevice *s,
    struct comedi_insn *insn,
    uint32_t * data)
{
    struct daqbmc_private *devpriv = dev->private;
    int32_t ret = -EBUSY;
    int32_t n;

    if (unlikely(!devpriv)) {
        return -EFAULT;
    }

    mutex_lock(&devpriv->cmd_lock);
    if (unlikely(test_bit(AI_CMD_RUNNING, &devpriv->state_bits))) { // Semaphore
        goto ai_read_exit;
    }

    devpriv->ai_hunk = false;

    devpriv->ai_chan = CR_CHAN(insn->chanspec);
    devpriv->ai_range = CR_RANGE(insn->chanspec);

    /* convert n samples */
    for (n = 0; n < insn->n; n++) {
        data[n] = daqbmc_ai_get_sample(dev, s);
    }
    ai_count = devpriv->ai_count;
    ret = 0;
ai_read_exit:
    mutex_unlock(&devpriv->cmd_lock);
    smp_mb__after_atomic();
    return ret ? ret : insn->n;
}
Why "smp_mb__after_atomic()" is needed for with multi-core systems.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0124r1.html
https://docs.kernel.org/core-api/wrappers/atomic_t.html
 

MrChips

Joined Oct 2, 2009
34,625
This is a different meaning than the software / multitasking meaning. Semaphore in this context is the same as a mutex.

Its implementation is a lot more complicated than a just a binary flag, and is typically done with an atomic read / write operation on sophisticated processors. On single-processor micros, it is often implemented by turning off interrupts, then checking and updating a memory location.
You are correct. But the fundamental origin of the semaphore is a binary flag. You can add all sorts of conditions on to a flag and call it a semaphore.

Mutexes and semaphores are synchronization tools used to manage concurrent access to shared resources.

Reference: https://www.geeksforgeeks.org/operating-systems/mutex-vs-semaphore/
 

Thread Starter

MTech1

Joined Feb 15, 2023
181
So what I think is, when multiple tasks want to access the same shared resource we need to protect it, otherwise the data can get corrupted. If both tasks try at the same time, a mutex will allow only one task to enter while the other gets blocked until the first one finishes.

In the same way, a binary semaphore also makes sure that when two tasks want the same resource, only one gets it. Once the first task is done, it signals and then the waiting task can take control.

Because of that, I honestly don’t see much of a difference between a mutex and a binary semaphore in this case.
 

Futurist

Joined Apr 8, 2025
720
So what I think is, when multiple tasks want to access the same shared resource we need to protect it, otherwise the data can get corrupted. If both tasks try at the same time, a mutex will allow only one task to enter while the other gets blocked until the first one finishes.

In the same way, a binary semaphore also makes sure that when two tasks want the same resource, only one gets it. Once the first task is done, it signals and then the waiting task can take control.

Because of that, I honestly don’t see much of a difference between a mutex and a binary semaphore in this case.
Here's the core differences:

1758048127507.png
 
Top