C Mastery / False Sharing in Concurrent Programs
Part 10 — Concurrency

False Sharing in Concurrent Programs

This chapter focuses on false sharing specifically in multithreaded code, with concrete fixes and detection.

Why This Matters

False sharing silently serializes parallel code: two threads update distinct variables, yet the cache-coherence traffic makes them slow. It is one of the most common reasons a multithreaded program fails to scale.

Prerequisites

Core Concept

Two threads writing different variables that share a cache line cause false sharing: each write invalidates the other core's copy of the line, forcing repeated cache-coherence traffic. The threads never touch the same byte, but the hardware treats the line as one unit.

struct {
    int a;   /* thread 1 */
    int b;   /* thread 2 */
} counters;  /* a and b on the same cache line (usually 64 bytes) */

Examples

Detecting and fixing

#include <stdalign.h>

struct alignas(64) Counter {
    int value;
};

static struct Counter c1;
static struct Counter c2;   /* now on different cache lines */

_Alignas(64) (C11) forces each counter to its own cache line. On platforms where the cache line is not exactly 64, a larger power-of-two alignment (128) is a safe over-estimate.

Padding without _Alignas

struct Counter {
    int value;
    char pad[64 - sizeof(int)];
};

This is more error-prone; prefer _Alignas.

How It Works

The cache-coherence protocol (MESI and variants) keeps lines coherent. When a core writes a byte in a line, it must invalidate that line in other cores. Two writers to the same line ping-pong the line between caches, even for different bytes.

Variations

Per-thread accumulation

Compute per-thread partial results in thread-local storage, then combine once at the end, avoiding shared counters entirely.

Padding to cache-line size

_Alignas(64) or _Alignas(128) separates hot per-thread variables.

Common Mistakes

Undefined Behavior

Portability

(64 or 128).

Under the Hood

perf c2c (Linux) analyzes cache-coherency traffic and identifies false sharing. Hardware performance counters reveal cache-line invalidations.

Practical Usage

Exercises

1. Write a two-thread program that increments two adjacent counters, measure with perf c2c, then fix with _Alignas(64). 2. Compare scaling before and after the fix. 3. Implement per-thread accumulation and compare.

Deep Challenge

Explain why _Atomic counters do not prevent false sharing, and show how to fix a pair of atomic counters that are falsely shared. Then measure the difference with perf c2c.

References

Verification

verified.`

Progress

Concept checkboxes

Mastery levels

ConceptCurrent level (0–8)Target level
c.conc.false-sharing06