Semaphore vs Mutex: Key Differences and When to Use Each
mutex is a locking mechanism that allows only one thread to access a resource at a time, ensuring exclusive access. A semaphore is a signaling mechanism that controls access to a resource by multiple threads using a counter, allowing a limited number of threads to enter concurrently.Quick Comparison
Here is a quick side-by-side comparison of semaphore and mutex based on key factors.
| Factor | Mutex | Semaphore |
|---|---|---|
| Purpose | Ensures exclusive access to a resource | Controls access to a resource by multiple threads |
| Access | Only one thread can hold the mutex at a time | Multiple threads can acquire if count > 0 |
| Counter | Binary (locked/unlocked) | Integer count (can be >1) |
| Ownership | Owned by the thread that locks it | No ownership required |
| Use case | Protect critical sections | Limit number of concurrent accesses |
| Blocking behavior | Blocks if already locked | Blocks if count is zero |
Key Differences
Mutex is a locking tool designed to provide exclusive access to a shared resource. Only one thread can lock the mutex at a time, and other threads must wait until it is unlocked. It has ownership, meaning the thread that locks it must unlock it, which helps prevent accidental release by other threads.
On the other hand, a semaphore uses a counter to allow multiple threads to access a resource concurrently up to a set limit. It does not have ownership, so any thread can signal (release) the semaphore. This makes semaphores useful for managing pools of resources like connections or slots.
In summary, use a mutex when you need strict exclusive access and ownership control, and use a semaphore when you want to limit concurrent access but allow multiple users simultaneously.
Code Comparison
This example shows how a mutex protects a critical section so only one thread prints at a time.
#include <pthread.h> #include <stdio.h> #include <unistd.h> pthread_mutex_t lock; void* worker(void* arg) { pthread_mutex_lock(&lock); printf("Thread %ld entered critical section\n", (long)arg); sleep(1); // simulate work printf("Thread %ld leaving critical section\n", (long)arg); pthread_mutex_unlock(&lock); return NULL; } int main() { pthread_t threads[3]; pthread_mutex_init(&lock, NULL); for (long i = 1; i <= 3; i++) { pthread_create(&threads[i-1], NULL, worker, (void*)i); } for (int i = 0; i < 3; i++) { pthread_join(threads[i], NULL); } pthread_mutex_destroy(&lock); return 0; }
Semaphore Equivalent
This example uses a semaphore to allow up to two threads to enter the critical section concurrently.
#include <pthread.h> #include <semaphore.h> #include <stdio.h> #include <unistd.h> sem_t sem; void* worker(void* arg) { sem_wait(&sem); printf("Thread %ld entered critical section\n", (long)arg); sleep(1); // simulate work printf("Thread %ld leaving critical section\n", (long)arg); sem_post(&sem); return NULL; } int main() { pthread_t threads[4]; sem_init(&sem, 0, 2); // allow 2 concurrent threads for (long i = 1; i <= 4; i++) { pthread_create(&threads[i-1], NULL, worker, (void*)i); } for (int i = 0; i < 4; i++) { pthread_join(threads[i], NULL); } sem_destroy(&sem); return 0; }
When to Use Which
Choose a mutex when you need to protect a resource so that only one thread can use it at a time, such as updating shared data or critical sections. Its ownership feature helps avoid accidental unlocking by other threads.
Choose a semaphore when you want to limit the number of threads accessing a resource simultaneously, like controlling access to a fixed-size pool of connections or slots. Semaphores are better for managing multiple identical resources.