Table of Contents

Mutex

A mutex (mutual exclusion lock) allows only one thread at a time to hold it. A thread that calls lock() while another thread already owns the mutex blocks until the owner calls unlock(). This is the simplest and most common way to protect a critical section: a block of code that touches shared state and must not run concurrently with itself.

#include <pthread.h>
 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int shared_counter = 0;
 
void increment(void) {
    pthread_mutex_lock(&mutex);
    shared_counter++;
    pthread_mutex_unlock(&mutex);
}

Ownership

Unlike a semaphore, a mutex has a notion of ownership: only the thread that locked it is allowed to unlock it. Most implementations enforce this and treat an unlock by a non-owner as a bug, since the whole point of a mutex is that exactly one specific thread is responsible for the critical section at any time. This is also why a mutex can't be used directly to signal between two different threads (thread A locks, thread B unlocks); a semaphore or condition variable is the right tool for that.

Blocking vs spinning

A mutex is a blocking primitive: a thread that fails to acquire it is descheduled by the OS rather than burning CPU cycles retrying. This is efficient when the critical section is long or contention is high, since a blocked thread frees the core for other work. When the critical section is very short and contention is low, the cost of two context switches (block, then wake) can exceed the cost of just spinning briefly, which is the tradeoff a Spinlock makes instead. Some implementations (Linux futexes, for example) spin briefly before falling back to blocking, to get the best of both.