← Back to examples

False Sharing: why more threads can be slower

Two threads each increment their own counter — they never touch each other's data. Yet if both counters sit on the same 64-byte cache line, every write invalidates the other core's copy and the line ping-pongs between caches. Pad them onto separate lines and the contention vanishes. Press Run and watch the same work finish at very different speeds.

Same cache line false sharing

struct { long a; long b; }a and b are 8 bytes apart, so they share one line.
one 64-byte cache line
a · Core 0
b · Core 1
pad
pad
pad
pad
line owned by: Core 0
increments done0
cache-line transfers0
time0.0s

Padded — separate lines fixed

struct { long value; char pad[56]; } — each counter fills its own 64-byte line.
two separate cache lines
a · Core 0
pad
pad
b · Core 1
pad
pad
each core owns its line: Core 0 | Core 1
increments done0
cache-line transfers0
time0.0s

The point: both versions do the exact same increments and share no data logically. The only difference is 56 bytes of padding — but that keeps the two counters on different cache lines, so the cores never invalidate each other. False sharing is invisible in your source code and lives entirely in the hardware's 64-byte-line bookkeeping. The even-better fix: accumulate into a local variable and write the shared result once (an OpenMP reduction).