Master Linux Synchronization: From Semaphores to Mutexes with Practical Code
Learn the core principles of synchronization and mutual exclusion in multi‑process or multi‑threaded Linux environments, explore design concepts such as atomic operations and deadlock avoidance, and see complete POSIX‑thread code examples using semaphores, condition variables, mutexes and spinlocks.
Synchronization
Synchronization coordinates multiple threads or processes so that they execute in a defined order or wait for specific conditions, guaranteeing correct access to shared resources.
Design principles
Atomic operations: Indivisible actions that either complete fully or not at all, forming the basis of safe concurrent execution.
Mutual exclusion: Guarantees that only one thread or process can access a shared resource at any given time.
Condition waiting: Allows a thread to block until a particular condition becomes true; another thread signals it to continue.
Order preservation: Controls execution order to meet expected sequencing requirements.
Linux implementation
Semaphores: Use sem_init, sem_wait and sem_post to count resources and limit concurrent access.
Condition variables: Use pthread_cond_init, pthread_cond_wait and pthread_cond_signal to block and wake threads based on conditions.
Mutex
A mutex (mutual exclusion lock) ensures exclusive access to a shared resource; only one thread may hold the lock at a time.
Design principles
Mutex lock: The lock itself that serializes access.
Critical section: The code region protected by the mutex where shared data is accessed.
Deadlock avoidance: Design the locking strategy to prevent circular‑wait situations.
Linux implementation
POSIX mutex: Functions pthread_mutex_init, pthread_mutex_lock and pthread_mutex_unlock manage the lock lifecycle.
Spinlock: Functions spin_lock and spin_unlock provide a busy‑wait lock that does not yield the CPU.
Example: Producer‑Consumer with a bounded buffer
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define BUFFER_SIZE 5
int buffer[BUFFER_SIZE];
int count = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_producer = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_consumer = PTHREAD_COND_INITIALIZER;
void *producer(void *arg) {
for (int i = 0; i < 10; ++i) {
pthread_mutex_lock(&mutex);
while (count == BUFFER_SIZE) {
pthread_cond_wait(&cond_producer, &mutex);
}
buffer[count++] = i;
printf("Produced: %d
", i);
pthread_cond_signal(&cond_consumer);
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
void *consumer(void *arg) {
for (int i = 0; i < 10; ++i) {
pthread_mutex_lock(&mutex);
while (count == 0) {
pthread_cond_wait(&cond_consumer, &mutex);
}
int item = buffer[--count];
printf("Consumed: %d
", item);
pthread_cond_signal(&cond_producer);
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
int main() {
pthread_t producer_thread, consumer_thread;
pthread_create(&producer_thread, NULL, producer, NULL);
pthread_create(&consumer_thread, NULL, consumer, NULL);
pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond_producer);
pthread_cond_destroy(&cond_consumer);
return 0;
}Example: Incrementing a shared counter with two threads
#include <stdio.h>
#include <pthread.h>
int counter = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void* increment_counter(void* arg) {
for (int i = 0; i < 100000; ++i) {
pthread_mutex_lock(&mutex);
counter++;
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
int main() {
pthread_t t1, t2;
pthread_create(&t1, NULL, increment_counter, NULL);
pthread_create(&t2, NULL, increment_counter, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_mutex_destroy(&mutex);
printf("Final Counter Value: %d
", counter);
return 0;
}Key points when using mutexes:
Initialize with PTHREAD_MUTEX_INITIALIZER or pthread_mutex_init.
Lock with pthread_mutex_lock before entering a critical section and unlock with pthread_mutex_unlock after leaving it.
Destroy the mutex with pthread_mutex_destroy when it is no longer needed.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
