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.
struct { long a; long b; } — a and b are 8 bytes apart, so they share one line.struct { long value; char pad[56]; } — each counter fills its own 64-byte line.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).