0
0
Power-electronicsComparisonBeginner · 4 min read

Semaphore vs Mutex in Embedded C: Key Differences and Usage

In embedded C, a mutex is a locking mechanism used to ensure exclusive access to a resource by one task at a time, while a semaphore can allow multiple tasks to access a resource up to a set limit. Mutexes are mainly for mutual exclusion, and semaphores can be used for signaling or counting available resources.
⚖️

Quick Comparison

This table summarizes the main differences between semaphore and mutex in embedded C.

FeatureMutexSemaphore
PurposeMutual exclusion (single owner)Resource counting or signaling
OwnershipOwned by the task that locks itNo ownership, any task can signal or wait
ValueBinary (locked/unlocked)Integer count (0 to max count)
Use caseProtect shared dataControl access to limited resources or event signaling
Priority inversion handlingUsually supports priority inheritanceUsually no priority inheritance
Blocking behaviorTask blocks if mutex is lockedTask blocks if count is zero
⚖️

Key Differences

Mutex is designed to provide exclusive access to a resource by allowing only one task to own it at a time. It has ownership, meaning the task that locks the mutex must unlock it. This helps prevent race conditions when multiple tasks share data.

Semaphore is more general and can be used as a counter to control access to multiple instances of a resource or for signaling between tasks. It does not have ownership, so any task can signal (release) or wait (acquire) the semaphore.

In embedded C, mutexes often support priority inheritance to avoid priority inversion problems, where a low-priority task holds a mutex needed by a higher-priority task. Semaphores usually do not have this feature. Also, mutexes are binary (locked/unlocked), while semaphores can have a count greater than one.

⚖️

Code Comparison

Here is an example of using a mutex in embedded C to protect a shared variable.

embedded_c
#include <stdio.h>
#include <pthread.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int shared_data = 0;

void* task(void* arg) {
    pthread_mutex_lock(&mutex);
    shared_data++;
    printf("Mutex locked: shared_data = %d\n", shared_data);
    pthread_mutex_unlock(&mutex);
    return NULL;
}

int main() {
    pthread_t t1, t2;
    pthread_create(&t1, NULL, task, NULL);
    pthread_create(&t2, NULL, task, NULL);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    return 0;
}
Output
Mutex locked: shared_data = 1 Mutex locked: shared_data = 2
↔️

Semaphore Equivalent

Here is an example of using a semaphore in embedded C to control access to a resource count.

embedded_c
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>

sem_t semaphore;
int shared_data = 0;

void* task(void* arg) {
    sem_wait(&semaphore);
    shared_data++;
    printf("Semaphore acquired: shared_data = %d\n", shared_data);
    sem_post(&semaphore);
    return NULL;
}

int main() {
    sem_init(&semaphore, 0, 1); // Binary semaphore
    pthread_t t1, t2;
    pthread_create(&t1, NULL, task, NULL);
    pthread_create(&t2, NULL, task, NULL);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    sem_destroy(&semaphore);
    return 0;
}
Output
Semaphore acquired: shared_data = 1 Semaphore acquired: shared_data = 2
🎯

When to Use Which

Choose a mutex when you need strict mutual exclusion with ownership and priority inheritance to protect shared data from concurrent access. This is ideal for critical sections where only one task should run at a time.

Choose a semaphore when you need to manage access to a limited number of identical resources or for signaling events between tasks without ownership constraints. Semaphores are better for counting resources or simple task synchronization.

Key Takeaways

Mutexes provide exclusive access with ownership and priority inheritance, ideal for protecting shared data.
Semaphores can count resources and signal between tasks without ownership, useful for resource management.
Mutexes are binary locks; semaphores can have counts greater than one.
Use mutexes for critical sections needing strict locking; use semaphores for resource counting or signaling.
Priority inversion is handled by mutexes but usually not by semaphores.