Linux Kernel Locks: Semaphores, Mutexes, RWLocks, Atomics, Spinlocks & Barriers
The article categorizes Linux kernel synchronization primitives by their target—critical sections, CPUs, memory, or cache—detailing atomic variables, spinlocks, semaphores, mutexes, read‑write locks, preemption, RCU, and memory barriers, explaining their mechanisms, trade‑offs, and typical kernel usage examples.
Atomic Variables and Spinlocks – CPU
Atomic variables provide lock‑free, chip‑level atomicity for read‑modify‑write sequences on multi‑core x86 systems using the lock instruction. A typical declaration is atomic_int x; or atomic<int> x;. Spinlocks protect data on multi‑CPU systems by busy‑waiting when the lock is already held, avoiding the overhead of sleeping.
#include <linux/spinlock.h>
spinlock_t my_lock;
void my_function(void)
{
spin_lock(&my_lock);
// access shared resource
spin_unlock(&my_lock);
}If a thread fails to acquire a spinlock it loops, continuously checking the lock state. This yields lower latency than a mutex when the critical section is very short, but excessive spinning on many CPUs reduces overall performance.
Semaphores and Mutexes – Critical Section
Semaphores are counting resources. A semaphore value of 3 indicates three available resources; sem_wait() decrements the count (blocking if zero) and sem_post() increments it (unblocking waiting threads). The kernel implements a semaphore as:
struct semaphore {
spinlock_t lock; // protects the semaphore itself
unsigned int count;
struct list_head wait_list;
};Mutexes allow only one thread into the critical section. When a thread cannot obtain the mutex it is put to sleep, causing a context switch to kernel mode and later a wake‑up when the mutex becomes available. A timed mutex ( std::timed_mutex) can give up after a specified timeout using try_lock_for():
std::timed_mutex g_mutex;
if (g_mutex.try_lock_for(std::chrono::seconds(2))) {
// do something
} else {
std::cout << "lock acquisition failed";
}Read‑Write Locks – Critical Section
Read‑write locks separate read and write protection, allowing multiple concurrent readers while restricting writers to exclusive access. This reduces lock granularity in read‑heavy workloads and can be implemented on top of spinlocks.
Preemption – CPU
Kernel preemption is tracked by the preempt_count field: it is incremented on lock acquisition and decremented on release. When the count is zero the kernel may preempt the current task; a non‑zero value disables preemption.
Per‑CPU Variables – Cache
Per‑CPU variables solve cache‑coherency issues by giving each CPU its own instance of a variable, avoiding false sharing and ensuring that updates are visible only after explicit synchronization.
RCU Mechanism and Memory Barriers – Memory
Read‑Copy‑Update (RCU) permits many readers to access data concurrently while writers work on a copy and replace the original atomically. The core steps are (1) copy the data, (2) modify the copy, and (3) atomically switch the pointer, followed by deferred reclamation of the old memory.
Memory barriers enforce ordering of memory operations. The kernel provides generic barriers ( mb()), write‑only barriers ( wmb()), and read‑only barriers ( rmb()). Example macro definitions:
#define mb() _asm__volatile("mfence" ::: "memory")
#define barrier() __asm__ __volatile__("" ::: "memory")In C++11, std::atomic_thread_fence(std::memory_order_acquire) and std::atomic_thread_fence(std::memory_order_release) provide similar semantics. The acquire fence guarantees that subsequent reads/writes are not reordered before the fence; the release fence guarantees prior operations are completed before the fence.
Kernel Usage Examples
Locks are used throughout the kernel to protect critical data structures:
Process scheduling:
spin_lock(&rq->lock); … spin_unlock(&rq->lock);File system metadata:
spin_lock(&inode->i_lock); … spin_unlock(&inode->i_lock);Network stack:
read_lock(&rt_hash_lock); … read_unlock(&rt_hash_lock);Memory management:
spin_lock(&mm->page_table_lock); … spin_unlock(&mm->page_table_lock);These examples illustrate how each lock type fits a specific synchronization need within the Linux kernel.
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.
Linux Code Review Hub
A professional Linux technology community and learning platform covering the kernel, memory management, process management, file system and I/O, performance tuning, device drivers, virtualization, and cloud computing.
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.
