Synchronization with POSIX Threads
Explore how to use POSIX threads synchronization mechanisms including mutexes for mutual exclusion, condition variables for signaling, semaphores for controlling resource access, and barriers for thread coordination. Understand how these tools help prevent race conditions and enable safe parallel programming in C.
Previously, we learned how multiple threads can execute concurrently within the same process using POSIX threads. Because these threads share the same memory space, they can read and modify the same variables. Without proper coordination, this can potentially lead to incorrect results.
In this lesson, we'll learn how synchronization by the pthreads library allows us to coordinate thread execution safely and predictably.
Mutual exclusion with mutexes
The most fundamental synchronization mechanism in pthreads is the mutex (short for mutual exclusion). A mutex protects a critical section, which is a portion of code that accesses shared data and must not be executed by more than one thread at a time. If one thread locks a mutex, any other thread attempting to lock the same mutex must wait until it is unlocked.
Consider a simple example in which multiple threads increment a shared counter:
#include <stdio.h>
#include <pthread.h>
#define NUM_THREADS 5
int counter = 0;
pthread_mutex_t lock;
void* increment(void* arg) {
pthread_mutex_lock(&lock);
counter++;
pthread_mutex_unlock(&lock);
return NULL;
}
int main() {
pthread_t threads[NUM_THREADS];
pthread_mutex_init(&lock, NULL);
for (int i = 0; i < NUM_THREADS; i++)
pthread_create(&threads[i], NULL, increment, NULL);
for (int i = 0; i < NUM_THREADS; i++)
pthread_join(threads[i], NULL);
pthread_mutex_destroy(&lock);
printf("Final counter value: %d\n", counter);
return 0;
}In the code above, the following lines of code implement mutual exclusion:
Line 7: We declare a mutex variable,
lock.Line 10:
pthread_mutex_lock()attempts to acquire the lock. If another thread already holds it, the calling thread waits.Line 12:
pthread_mutex_unlock()releases the lock so another ...