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 more than one thread to enter if the count permits.Quick Comparison
Here is a quick side-by-side comparison of mutex and semaphore based on key factors.
| Factor | Mutex | Semaphore |
|---|---|---|
| Purpose | Ensures exclusive access to a resource | Controls access to multiple instances of a resource |
| Access | Only one thread can hold the lock 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
A mutex is a simple locking tool that allows only one thread to enter a critical section at a time. It has a binary state: locked or unlocked. When a thread locks a mutex, other threads trying to lock it will wait until it is unlocked. The mutex is usually owned by the thread that locked it, which helps prevent errors like unlocking by a different thread.
On the other hand, a semaphore uses a counter to allow multiple threads to access a limited number of resources simultaneously. The counter decreases when a thread acquires the semaphore and increases when it releases it. If the counter reaches zero, threads trying to acquire the semaphore will block until another thread releases it. Semaphores do not have ownership, so any thread can release them.
In summary, use a mutex when you need exclusive access to a resource, and use a semaphore when you want to limit concurrent access to a resource pool.
Mutex Code Example
This example shows how a mutex ensures exclusive access to a shared counter in C using POSIX threads.
#include <pthread.h> #include <stdio.h> pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; int counter = 0; void* increment(void* arg) { for (int i = 0; i < 100000; i++) { pthread_mutex_lock(&lock); counter++; pthread_mutex_unlock(&lock); } return NULL; } int main() { pthread_t t1, t2; pthread_create(&t1, NULL, increment, NULL); pthread_create(&t2, NULL, increment, NULL); pthread_join(t1, NULL); pthread_join(t2, NULL); printf("Final counter value: %d\n", counter); return 0; }
Semaphore Equivalent
This example uses a semaphore to limit access to a resource pool of size 3 in C with POSIX threads.
#include <pthread.h> #include <semaphore.h> #include <stdio.h> #include <unistd.h> sem_t sem; void* worker(void* arg) { sem_wait(&sem); // Acquire semaphore printf("Thread %ld entered\n", (long)arg); sleep(1); // Simulate work printf("Thread %ld leaving\n", (long)arg); sem_post(&sem); // Release semaphore return NULL; } int main() { pthread_t threads[5]; sem_init(&sem, 0, 3); // Initialize semaphore with count 3 for (long i = 0; i < 5; i++) { pthread_create(&threads[i], NULL, worker, (void*)i); } for (int i = 0; i < 5; i++) { pthread_join(threads[i], NULL); } sem_destroy(&sem); return 0; }
When to Use Which
Choose a mutex when you need to protect a shared resource so that only one thread can access it at a time, such as updating a shared variable or writing to a file.
Choose a semaphore when you want to allow a limited number of threads to access a resource simultaneously, like controlling access to a fixed number of database connections or slots.
In short, use mutex for exclusive locking and semaphore for managing concurrent access limits.