False Sharing Mitigation
False sharing occurs when independent variables on the same cache line are written by different cores, making the cache coherency traffic thrash even though no data is actually shared; mitigation.
Definition
False sharing is the performance pathology where two threads write to different variables that happen to reside on the same CPU cache line, so that every write invalidates the other core cache line and the coherency protocol thrashes, and mitigation aligns each hot variable to its own cache line through padding.
Context and scope
Applied in high-performance counters, per-thread statistics, and any multi-threaded code where independent writers share a cache line by accident of layout.
Common misconceptions
- False sharing is a correctness bug — it is a performance bug; the program is correct, just slow, and the slowness is nondeterministic across hardware
- Padding always fixes false sharing — padding fixes it for one cache line size; a different CPU with a different line size can reintroduce it
Anti-patterns
- Padding every struct to a cache line, including single-threaded ones, wasting memory for no benefit
- Putting per-thread counters in an array without padding, so adjacent threads false-share and the counter update is 10x slower
Related concepts
Authoritative source
https://software.intel.com/articles/avoiding-and-identifying-false-sharing-among-threads
What it is
False sharing is the performance pathology where two threads write to different variables that happen to reside on the same CPU cache line, so that every write invalidates the other core cache line and the coherency protocol thrashes, and mitigation aligns each hot variable to its own cache line through padding. Applied in high-performance counters, per-thread statistics, and any multi-threaded code where independent writers share a cache line by accident of layout. The central difficulty is that interleaving is nondeterministic: the set of possible executions grows super-exponentially with the number of operations, and testing samples a vanishing fraction.
How it works
Correctness is established by reasoning about happens-before relationships, not by running more tests. Synchronization primitives are chosen for the specific guarantee needed — mutual exclusion, publication, or ordering — and composed only with a documented proof of absence of deadlock. Bounded resources apply backpressure rather than unbounded queuing that hides overload until memory exhausts.
When to apply and pitfalls
Apply whenever multiple flows share mutable state or resources. The dominant pitfall is reasoning sequentially about concurrent code — “this can’t happen because A finishes before B” — when in fact the scheduler can interleave at any instruction boundary. The second is using a coarse lock for simplicity and turning parallelism back into serialization.