Skip to main content

Semaphores in VxWorks: Binary, Counting, and Mutexes

·536 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.

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