← Back to list

From Correct to Fast: Optimizing Atomics with Cache Line Alignment

Atomics are safe, but not always fast — especially when multiple threads fight over the same cache line.

Pranjali Puranik · 2026-01-13 22:47 · 0 claps · 1.8 min read
#cplusplus #atomic-design #performance #high-performance #mutex
Open on Medium ↗
Wiki topics: SAF · Safety & Alignment

From Correct to Fast: Optimizing Atomics with Cache Line Alignment

Atomics are safe, but not always fast — especially when multiple threads fight over the same cache line.

What is an atomic?

In C++, std::atomic<T> provides thread-safe operations on a variable without using mutexes.

  • The operation is atomic, meaning no other thread can see a partially updated value.
std::atomic<int> counter;
counter.fetch_add(1); // thread-safe increment
  • std::atomic<int> guarantees correctness across threads, often via hardware instructions like lock xadd on x86 CPU, which is hardware-enforced atomicity. For assembly-level insight, check this Godbolt example.

Cache line:

CPUs do not read or write memory byte by byte. Instead they work with cache lines, typically 64 bytes.

Data is transferred between memory and cache in blocks of fixed size, called cache lines or cache blocks.

  • When it writes/reads, it locks or invalidates the entire cache line across cores for atomic operations.
  • This is why two variables in the same cache line can interfere, even if they’re logically unrelated.

This interference is called false sharing.

Benchmark: non-padded vs padded atomics

We can illustrate the impact of false sharing with a simple benchmark.

  1. Non-padded atomic array — likely all elements share the same cache line.
  2. Padded atomic array — each element gets its own 64-byte cache line.
#include <atomic>
#include <thread>
#include <vector>
#include <chrono>
#include <iostream>

constexpr int ITER = 10'000'000;
constexpr int THREADS = 4;

// Non-padded
std::atomic<int> arr[THREADS];

// Padded (64-byte alignment)
struct alignas(64) PaddedAtomic { std::atomic<int> value; };
PaddedAtomic paddedArr[THREADS];

void worker(std::atomic<int>* a){ for(int i=0;i<ITER;i++) a->fetch_add(1); }
void worker_padded(PaddedAtomic* a){ for(int i=0;i<ITER;i++) a->value.fetch_add(1); }

int main() {
    std::vector<std::thread> threads;

    auto start = std::chrono::high_resolution_clock::now();
    for(int i=0;i<THREADS;i++) threads.emplace_back(worker, &arr[0]); // All threads increment the same atomic -> causes false sharing
    for(auto& t: threads) t.join();
    auto end = std::chrono::high_resolution_clock::now();
    std::cout << "Non-padded time: " << std::chrono::duration<double>(end-start).count() << " s\n";

    threads.clear();
    start = std::chrono::high_resolution_clock::now();
    for(int i=0;i<THREADS;i++) threads.emplace_back(worker_padded, &paddedArr[i]);
    for(auto& t: threads) t.join();
    end = std::chrono::high_resolution_clock::now();
    std::cout << "Padded time: " << std::chrono::duration<double>(end-start).count() << " s\n";
}

Results on i7–12700K (20CPUS)

Results on i7–12700K (20CPUS)

That’s a 7x speedup just by avoiding false sharing.

Before (shared cache line): [arr0][arr1][arr2] … <- contention between threads

After (padded): [arr0………][arr1………][arr2………] <- each thread updates its own line

Key Takeaways:

  • Atomic operations guarantee correctness but are not free.
  • CPUs enforce cache-line-level exclusivity, so layout matters.
  • False sharing can slow down unrelated variables in the same line.
  • Use padding (alignas(64)) for frequently updated atomics in multithreaded code.

(Note: Illustrations are added with the help of godbolt.org and AI)


메타데이터
post_id
fc59dbe47269
slug
from-correct-to-fast-optimizing-atomics-with-cache-line-alignment-fc59dbe47269
url
https://medium.com/@bethe1tweets/from-correct-to-fast-optimizing-atomics-with-cache-line-alignment-fc59dbe47269
canonical_url
https://medium.com/@bethe1tweets/from-correct-to-fast-optimizing-atomics-with-cache-line-alignment-fc59dbe47269
author_url
https://medium.com/@bethe1tweets
status
ok
fetched_at
2026-06-26 12:24:55