Skip to main content

Semaphores in VxWorks: Binary, Counting, and Mutexes

·548 words·3 mins
VxWorks RTOS Semaphores Synchronization Mutex Embedded Systems Programming Tutorial
Table of Contents
VxWorks Programming Tutorial for Beginners - This article is part of a series.
Part 13: This Article

πŸš€ Introduction
#

Semaphores are one of the most important synchronization mechanisms in VxWorks.
They are used for:

  • Task synchronization β†’ coordinating execution order between tasks.
  • Resource protection β†’ ensuring only one task uses a resource at a time.

VxWorks provides three main types of semaphores:

  1. Binary Semaphores
  2. Counting Semaphores
  3. Mutexes (Mutual Exclusion Semaphores)

🧩 Types of Semaphores in VxWorks
#

1. Binary Semaphores
#

  • Simple lock/unlock mechanism (0 or 1).
  • Great for signaling events between tasks.

2. Counting Semaphores
#

  • Keep track of multiple resources.
  • Useful when several identical resources are available (e.g., buffer pool).

3. Mutexes
#

  • Special semaphores for mutual exclusion.
  • Provide priority inheritance to avoid priority inversion problems.

πŸ’» Example: Using Semaphores in VxWorks
#

We’ll demonstrate:

  1. A Binary Semaphore for task synchronization.
  2. A Counting Semaphore for managing resource pool.
  3. A Mutex for protecting a shared resource.

Code Example
#

#include <vxWorks.h>
#include <semLib.h>
#include <taskLib.h>
#include <stdio.h>

SEM_ID binSem;
SEM_ID countSem;
SEM_ID mutexSem;

// Task waiting for binary semaphore
void taskA()
{
    while (1)
    {
        semTake(binSem, WAIT_FOREVER);
        printf("Task A: Received signal from Task B\n");
    }
}

// Task signaling binary semaphore
void taskB()
{
    while (1)
    {
        taskDelay(100);
        semGive(binSem);
        printf("Task B: Signaled Task A\n");
    }
}

// Counting semaphore example
void resourceUser(int id)
{
    semTake(countSem, WAIT_FOREVER);
    printf("Task %d: Acquired resource\n", id);

    taskDelay(200);

    printf("Task %d: Released resource\n", id);
    semGive(countSem);
}

// Mutex example (shared counter)
int sharedCounter = 0;

void counterTask(int id)
{
    while (1)
    {
        semTake(mutexSem, WAIT_FOREVER);
        sharedCounter++;
        printf("Task %d: Incremented counter to %d\n", id, sharedCounter);
        semGive(mutexSem);

        taskDelay(50);
    }
}

void usrAppInit(void)
{
    // Binary semaphore (initially empty)
    binSem = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);

    // Counting semaphore with 2 resources
    countSem = semCCreate(SEM_Q_PRIORITY, 2);

    // Mutex semaphore
    mutexSem = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE);

    // Binary semaphore demo
    taskSpawn("tA", 100, 0, 4000, (FUNCPTR)taskA, 0,0,0,0,0,0,0,0,0,0);
    taskSpawn("tB", 110, 0, 4000, (FUNCPTR)taskB, 0,0,0,0,0,0,0,0,0,0);

    // Counting semaphore demo
    taskSpawn("tRes1", 120, 0, 4000, (FUNCPTR)resourceUser, 1,0,0,0,0,0,0,0,0,0);
    taskSpawn("tRes2", 130, 0, 4000, (FUNCPTR)resourceUser, 2,0,0,0,0,0,0,0,0,0);
    taskSpawn("tRes3", 140, 0, 4000, (FUNCPTR)resourceUser, 3,0,0,0,0,0,0,0,0,0);

    // Mutex demo
    taskSpawn("tCnt1", 150, 0, 4000, (FUNCPTR)counterTask, 1,0,0,0,0,0,0,0,0,0);
    taskSpawn("tCnt2", 160, 0, 4000, (FUNCPTR)counterTask, 2,0,0,0,0,0,0,0,0,0);
}

πŸ“ Explanation of the Code
#

  1. Binary Semaphore

    • Task B signals (semGive), Task A waits (semTake).
    • Ensures Task A only runs when Task B signals.
  2. Counting Semaphore

    • Allows two tasks to acquire the resource simultaneously.
    • Third task waits until one releases.
  3. Mutex

    • Protects the sharedCounter.
    • Ensures only one task updates it at a time.
    • Prevents priority inversion with SEM_INVERSION_SAFE.

⚑ What You’ll See
#

Sample output may look like:

Task B: Signaled Task A
Task A: Received signal from Task B
Task 1: Acquired resource
Task 2: Acquired resource
Task 3: Waiting...
Task 1: Released resource
Task 3: Acquired resource
Task 1: Incremented counter to 1
Task 2: Incremented counter to 2
Task 1: Incremented counter to 3
...

πŸ” Key Takeaways
#

  • Binary Semaphores β†’ great for signaling between tasks.
  • Counting Semaphores β†’ manage multiple identical resources.
  • Mutexes β†’ protect shared resources with priority inversion handling.

βœ… Wrap-Up
#

In this tutorial, you learned:

  • How to use binary semaphores for task synchronization.
  • How to use counting semaphores for resource management.
  • How to use mutexes for safe shared resource access.

In the next blog, we’ll explore Message Passing with Pipes in VxWorks β€” another powerful IPC mechanism.


πŸ‘‰ Stay tuned for Blog 14: β€œMessage Passing with Pipes in VxWorks.”

VxWorks Programming Tutorial for Beginners - This article is part of a series.
Part 13: This Article

Related

Using Semaphores for Task Synchronization in VxWorks
·434 words·3 mins
VxWorks RTOS Semaphores Task Synchronization Embedded Systems Programming Tutorial
Timers in VxWorks: Periodic and One-Shot Timers
·356 words·2 mins
VxWorks RTOS Timers Watchdog Embedded Systems Programming Tutorial
Shared Memory Communication in VxWorks
·460 words·3 mins
VxWorks RTOS IPC Shared Memory Embedded Systems Programming Tutorial