Linux - futex
A futex (short for Fast Userspace Mutex) is a fundamental Linux kernel mechanism used to build high-performance synchronization primitives—such as mutexes, semaphores, and condition variables—in user space.
The Problem Futex Solves
Traditional synchronization mechanisms required calling into the kernel (a system call) every time a thread wanted to lock or unlock a resource. Context switching between user space and kernel space is relatively slow and expensive.
In practice, most lock operations are uncontended—meaning no other thread is holding the lock when a thread requests it. A futex avoids kernel overhead by handling the fast (uncontended) case entirely in user space.
How Futex Works
A futex consists of two parts:
- An integer in user space: A standard 32-bit integer alignment-bound in shared or process memory that holds the lock state (e.g.,
0for unlocked,1for locked,2for locked with waiters). - A kernel-managed wait queue: A queue inside the Linux kernel where threads sleep if they fail to acquire the lock.
The Two Paths:
- Uncontended Path (Fast Path - No System Call):
A thread uses an atomic instruction (like
Compare-And-Swap/atomic_cmpxchg) directly on the integer in user space. If the lock is free, it acquires it in a few CPU instruction cycles without invoking the kernel. - Contended Path (Slow Path - Kernel System Call):
If another thread already holds the lock, the atomic operation fails. The thread then makes a
futex()system call with the operationFUTEX_WAIT, telling the kernel: "If the integer still equals X, put me to sleep." When the lock holder finishes, it callsfutex()withFUTEX_WAKEto wake up the sleeping threads.
Key Futex Operations
The futex(2) system call supports several operations, with the primary two being:
| Operation | Description |
|---|---|
FUTEX_WAIT |
Checks if the futex integer matches an expected value. If it matches, the calling thread is suspended until waked. If it doesn't match, it returns immediately to prevent race conditions. |
FUTEX_WAKE |
Wakes up a specified number of threads waiting on the futex address. |
FUTEX_REQUEUE |
Wakes up some waiters and moves the rest to a different futex queue (commonly used in pthread_cond_broadcast). |
FUTEX_LOCK_PI |
Priority-inheritance futex operation to prevent priority inversion bugs. |
Who Uses Futexes?
Application developers rarely call futex() directly. Instead, high-level threading libraries use futexes under the hood:
POSIX Threads (pthreads)(pthread_mutex_t,pthread_cond_t)- C++ Standard Library (
std::mutex,std::condition_variable) - Java Virtual Machine (JVM) (Java object monitors and
ReentrantLock) - Go Runtime (channels and
sync.Mutex)