The Seqlock Pattern: Lock-Free Reads for Write-Rare Data

2026-06-20

Most reader-writer locks penalize readers: they take a lock, touch a shared cache line, and serialize against other readers on the bus. For data that's read constantly but written rarely — system time, configuration, routing tables — that's a brutal tax. The seqlock (sequence lock) flips the deal: readers pay nothing on the fast path, and writers eat the cost.

The mechanism is a single monotonically increasing counter plus the protected data:

Readers never write to shared memory. No cache line bouncing, no atomic RMW, no contention between readers. The two counter reads bracket the data read like a tripwire: if a writer touched anything in between, the reader sees a mismatch and retries.

Real-world example: the Linux kernel uses seqlocks for jiffies and gettimeofday(). Millions of cores call gettimeofday() per second; the timekeeping code updates the clock source maybe 1000 times per second. With a mutex, every reader would serialize on a single cache line — catastrophic. With a seqlock, readers run in parallel and the timer interrupt handler is the only writer.

Rule of thumb: seqlocks win when the read:write ratio exceeds roughly 100:1 AND the protected data is small enough to read in a handful of instructions. If reads are long, retry probability under contention rises as P(retry) ≈ read_duration / write_interval, and you can livelock.

The non-obvious traps:

Use seqlocks for scalar snapshots: clocks, counters, small config structs. Reach for RCU when readers walk pointers. Reach for a mutex when writes are frequent or reads are slow.

Key Takeaway: Seqlocks make readers free by making them retry — perfect for tiny, write-rare data, dangerous for anything you'd dereference mid-read.

All newsletters