Jon Gjengset on the Cost of Concurrency Coordination

Why shared cache lines can make even read-heavy locks slow, and how a different data structure trades writer work for scalable reads.

JGJon Gjengset연사
채널
Jane Street
게시일
2026년 3월 25일
영상
46:35
읽기
6분
슬라이드
7
원문
영어
YouTube에서 열기
스크롤하면 영상이 오른쪽 아래로 작아져 계속 재생됩니다. 자막은 읽기 언어를 따릅니다.
읽기 언어2개 언어로 읽을 수 있음
이 글은 아직 한국어 번역이 없어 영어 원문으로 표시합니다.
요약

30초 요약

Jon Gjengset uses a small read-only benchmark to explain cache coherence, reader-writer lock contention and false sharing. He demonstrates the left-right data structure, then explains its memory, consistency and writer-side trade-offs and answers questions about hardware and synchronization implementations.

  1. 1A surprising read benchmarkA mutex-protected read falls sharply in throughput when a second core is added, and a reader-writer lock also scales poorly in this short critical section.
  2. 2Readers write lock stateReader-writer locks update a shared reader count, making cache-line ownership move among cores.
  3. 3Two copies and a pointerLeft-right lets readers use one copy while a writer updates the other and publishes it with a pointer swap.
  4. 4False sharing in practiceReader counters sharing a cache line caused a severe performance drop; aligning them separately fixed the observed benchmark.
  5. 5Trade-offs matterLeft-right consumes more memory, permits stale reads and has a single-writer design, so it is suitable only for some workloads.

핵심 정리

  1. A read lock can require writes to shared coordination state, creating contention among readers.
  2. Cache coherence operates on cache lines, so ownership transfers can dominate short critical sections.
  3. Left-right gives readers independent state and shifts work toward a less frequent writer.
  4. False sharing can make lock-free code contend when independent values share a cache line.
  5. Left-right trades memory and stronger consistency for read scalability and is not a universal replacement for locks.
  6. Choose and measure a synchronization design against the workload and consistency guarantees it needs.
전문

챕터별로 다듬은 전문 읽기

원본 자막만 보기
01

Are mutexes slow?

A read-only benchmark shows throughput dropping with more threads. A reader-writer lock does not automatically fix the problem.

I want to look beyond the claim that mutexes are slow and ask what the CPU actually does when threads coordinate. The examples use a little Rust, but the ideas apply more broadly to concurrent algorithms and performance.

Consider a shared counter that many threads only read. Each takes a mutex, reads the counter and releases the lock. A black-box operation prevents the compiler from optimizing the read away; no thread writes the counter itself.

In my benchmark one thread reaches roughly 250 million reads per second, but adding a second core drops throughput to about 25 million. Adding further threads leaves it low. A mutex serializes access, but this is worse than simply keeping the same throughput as more threads arrive.

A reader-writer lock might appear to solve a read-heavy workload. Yet in this example its throughput also drops sharply, and as readers increase it eventually performs worse than the mutex. To understand the result, we need to look at caches.

Mutex and reader-writer lock benchmark
슬라이드 1 / 7Mutex and reader-writer lock benchmarkBoth throughput curves fall as reader threads are added in this short read-only workload.
02

Caches and coherence

Gjengset explains cache hierarchy, MESI states and cache-line ownership. Shared writes require coordination among cores.

Main memory is far slower to access than a local CPU cache. Common processors have a hierarchy: a small per-core L1 cache, an intermediate L2 and a larger L3 often shared among cores. Exact arrangements vary by processor.

When different cores cache the same memory, a coherence protocol coordinates their access. MESI is a useful model: Modified means a core has a changed exclusive copy; Exclusive means its sole copy is clean; Shared means multiple valid copies agree; Invalid means a cached entry cannot be used.

Coherence operates on cache lines, commonly 64-byte chunks in the example, not individual variables. Before a core writes shared data, it must obtain exclusive ownership and invalidate other copies. That requires cross-core communication.

Per-core and shared caches
슬라이드 2 / 7Per-core and shared cachesThe diagram shows private core caches alongside a shared L3 cache and main memory.
03

Why read locks contend

Readers update a shared counter when acquiring and releasing locks. Cache-line transfers can dominate very short critical sections.

A reader-writer lock typically maintains a shared reader count. Acquiring a read lock increments it and releasing decrements it, so even readers write the same shared cache line. With many cores, ownership moves repeatedly between them, introducing a sequential coordination cost.

For two readers, imagine core 0 owns the line and increments the count. Core 1 then needs the updated line to increment it; when core 0 releases, the line may have to move back so it can decrement. One acquisition and release can involve two cache-line transfers.

Two readers acquiring a read lock
슬라이드 3 / 7Two readers acquiring a read lockThe sequence illustrates cache-line ownership moving as readers update the shared count.

In the example, a local L1 access is about one nanosecond and a cross-core transfer roughly 30 nanoseconds; two transfers are already a large fraction of an approximately 100-nanosecond main-memory access. These are illustrative timings, not universal constants.

With a mutex, the holder has exclusive access until it releases, so the same reader-count ping-pong does not arise in the same way. A reader-writer lock can therefore scale worse in this particular short read-only benchmark, despite allowing multiple readers inside the protected region.

For a longer critical section, the work done under a lock can dwarf the acquisition overhead, and a mutex may be entirely appropriate. The trouble becomes prominent in hot, highly contended loops with very short critical sections. Real workloads need measurement.

04

The left-right alternative

Two copies and per-reader counters reduce contention for read-heavy workloads. The writer waits for old readers before reusing a copy.

As an alternative with different trade-offs, I used left-right in my PhD work, where reads vastly outnumbered writes and each read was a short hash-map lookup. The aim was to keep readers from repeatedly writing a shared cache line, shifting more work to the rare writer.

Two copies for left-right
슬라이드 4 / 7Two copies for left-rightReaders access the copy selected by a pointer while the writer owns the other copy.

Left-right holds two copies of the data and an atomic pointer to the copy readers should use. The writer changes the other copy and then swaps the pointer. Readers starting afterward use the newly published copy; existing readers may still be using the old one.

Before modifying the old copy, the writer must know that earlier readers have finished with it. Each reader has its own counter, ideally on a separate cache line. The writer scans these counters after the swap to determine when it is safe to proceed.

Readers do not update a shared reader count or coordinate with one another. Their local counter can stay owned by their core except when a writer examines it. Reads can proceed without waiting for a concurrent writer; in this design the read path is wait-free.

Left-right read scaling
슬라이드 5 / 7Left-right read scalingThe benchmark compares read throughput as reader threads increase.

The read-only benchmark scales roughly linearly with reader threads, reaching around three billion operations per second in the example. That follows from keeping readers independent, but the benefit depends on writes being rare.

An audience member asks about a dormant reader. I clarify that each reader increments its counter at the beginning and end of an operation; the writer can recognize an inactive reader from an even count or a changed counter. A reader that remains inside an operation can delay the writer, though it does not stop other readers.

05

False sharing and trade-offs

A benchmark regression reveals counters sharing a cache line. Gjengset discusses memory, writer and consistency costs of left-right.

Frequent writes introduce more contention and writer work. With more writes than reads, left-right can perform worse than a reader-writer lock. It was designed to exploit a particular workload, not to win every benchmark.

While benchmarking, I found an unexpected roughly tenfold drop at four cores. The cause was false sharing: independent reader counters had landed on the same 64-byte cache line, so separate writes still moved ownership of that whole line between cores.

False sharing and alignment
슬라이드 6 / 7False sharing and alignmentAligning reader counters to separate cache lines removes the observed contention.

Adding 64-byte alignment to the counter type put counters on separate lines and fixed the observed problem. The lesson is that lock-free does not mean contention-free: hardware can still force cores to coordinate even when the program contains no lock.

Choose a concurrent algorithm for the actual data-transfer pattern, rather than picking the fastest-looking primitive from a benchmark. Left-right is not a drop-in replacement: two data copies cost memory; readers may see stale values; and the design supports a single writer unless additional synchronization is added.

Left-right trade-offs
슬라이드 7 / 7Left-right trade-offsThe slide lists memory, stale reads, single-writer and other constraints.

The writer can wait until readers have moved to the new copy, at an added cost. Updates also need deterministic operations and a log that can replay changes to the other copy; otherwise the copies diverge. The writer must wait for readers still using the old copy.

Left-right offers eventual consistency rather than linearizability, so I would consider it for caches or lookups, not financial transactions. It may not guarantee reading your own write immediately. Mutexes, reader-writer locks and left-right each make sense for different requirements.

06

Choosing and measuring

Workload ratios, critical-section length and consistency requirements inform the choice. Coordination rather than the lock interface alone drives cost.

Ask about read-to-write ratio, critical-section length, thread count and consistency requirements. Can readers tolerate stale data? Must they see their own writes or satisfy linearizability? Measure before optimizing, and use the answers to choose a design.

The main cost is coordination caused by cache coherence, with locks being one interface through which it appears. Other designs, including scalable reader-writer locks with per-core counters, can move coordination costs to writers. The right choice depends on the workload.

07

Audience questions

Questions cover hardware advances, reader registration, mutex implementations and compiler ordering barriers. Gjengset distinguishes known behavior from uncertain hardware details.

Asked about hardware advances, I mention improvements to MESI-like protocols and three-dimensional cache packaging, which can increase nearby cache capacity. I also describe research into combining fetch-add operations, while noting that proprietary implementations make current hardware details difficult to verify.

An audience member asks about readers joining and leaving left-right. Its current reader list is protected by a mutex during registration; existing readers do not take that mutex on every read. A lock-free list could reduce registration contention if it became a bottleneck, with care around the writer’s post-swap scan.

On mutex implementations, I describe Linux futex support and optimizations that reduce lock size. Packing small locks together can itself cause false sharing. Reader-writer locks retain more implementation variation, including approaches with per-core reader state.

Asked about compiler optimization, I explain that synchronization implementations use ordering barriers to prevent reads or writes moving across a lock in unsafe ways. Some constraints apply to the compiler, some to the CPU, and some to both; the implementation must provide the appropriate ordering.

같은 채널의 다른 글

슬라이드 6장15:33EN
JSJane Street· 2026년 10월 26일Figgie Strategy: Reading Hands, Winning Majorities and Pricing CardsBradley, Mike · Jane StreetJane Street traders Bradley and Mike analyze three games to show how private information, market competition and timing affect card prices.Decision MakingMathematicsFintech
1:48:29EN
JSJane Street· 2026년 10월 16일How AI Is Changing Programming: John Krazit and Ron MinskyRon Minsky, John Krazit · Jane StreetJane Street’s AI tooling lead and the Signals and Threads host examine agent infrastructure, security, code review and the changing experience of writing software.코딩 에이전트Developer productivity평가(Evals)+2
1:36:37EN
JSJane Street· 2026년 9월 23일Aaron Bauer on Teaching Software Engineering in the Age of AIRon Minsky, Aaron Bauer · Jane StreetHow learning goals, active practice and editor design shape engineering education when models can generate the code.AI in EducationSoftware engineeringEducation+2
슬라이드 9장1:05:45EN
JSJane Street· 2026년 9월 11일Cyrus Omar on Live Programming and a Computational Commons for Humans and AICyrus OmarA demonstration of Hazel shows how immediate feedback, structured collaboration and carefully scoped permissions could support people and AI agents working together.Programming LanguagesHuman-AI Collaboration개발 워크플로와 테스트+2
1:25:00EN
JSJane Street· 2026년 9월 2일Eric Mannes on Turning Messy External Data Into Trading ResearchRon, Eric Mannes · Jane StreetFrom commodity futures and an Excel risk system to point-in-time datasets and AI, Eric Mannes explains the domain knowledge behind data engineering at Jane Street.Data quality & curation개발 워크플로와 테스트Investing+2
슬라이드 7장1:16:29EN
JSJane Street· 2026년 8월 26일Grant Sanderson and Alok Puranik: Positional Encodings Through Group TheoryGrant Sanderson, Alok Puranik · 3Blue1BrownStarting with assumptions about attention, they derive matrix exponentials and connect rotations, decay and Jordan blocks to RoPE and ALiBi.Transformers & attentionMathematics머신러닝 기초+1