atomic bool
atomic flag
C++
multithreading
concurrency

difference between standard's atomic bool and atomic flag

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

std::atomic<bool> and std::atomic_flag both represent boolean-like shared state, but they are not interchangeable. std::atomic<bool> is a full atomic type with normal load and store operations, while std::atomic_flag is a specialized minimal flag type intended for very low-level synchronization patterns.

What std::atomic<bool> Provides

std::atomic<bool> behaves like an atomic wrapper around a boolean value. It supports the standard atomic interface, which makes it flexible and easy to use in application code.

cpp
1#include <atomic>
2#include <thread>
3#include <iostream>
4
5std::atomic<bool> ready{false};
6
7int main() {
8    std::thread worker([] {
9        while (!ready.load(std::memory_order_acquire)) {
10        }
11        std::cout << "work started\n";
12    });
13
14    ready.store(true, std::memory_order_release);
15    worker.join();
16}

With std::atomic<bool>, you can load, store, exchange, and perform compare-and-exchange operations. That makes it suitable for state flags, cancellation signals, and one-bit conditions that still need a complete atomic API.

What std::atomic_flag Provides

std::atomic_flag is lower level. It is guaranteed to be lock-free and is centered around test-and-set style operations. Historically, the core interface was test_and_set() and clear(), which is enough to implement simple spin-based coordination.

cpp
1#include <atomic>
2
3std::atomic_flag lock = ATOMIC_FLAG_INIT;
4
5void acquire() {
6    while (lock.test_and_set(std::memory_order_acquire)) {
7    }
8}
9
10void release() {
11    lock.clear(std::memory_order_release);
12}

This works as a tiny spinlock, although spinlocks are usually a poor default for general application code because they waste CPU while waiting.

The important design point is that atomic_flag is not meant to be a drop-in replacement for an atomic boolean variable. It is a minimal primitive.

Key Differences in Practice

The biggest differences are interface and intent.

  • 'std::atomic<bool> stores a boolean value and supports regular atomic reads and writes.'
  • 'std::atomic_flag supports a minimal flag protocol centered on setting and clearing.'
  • 'std::atomic_flag is guaranteed lock-free by the standard.'
  • 'std::atomic<bool> may be lock-free on many platforms, but that is not guaranteed in all implementations.'

If you need to ask "what is the current value?" then std::atomic<bool> is usually the better fit. If you need the smallest guaranteed lock-free flag primitive for a low-level algorithm, std::atomic_flag may be appropriate.

Choosing the Right Type

Use std::atomic<bool> for straightforward program state:

cpp
1std::atomic<bool> stop_requested{false};
2
3void request_stop() {
4    stop_requested.store(true, std::memory_order_release);
5}
6
7bool should_stop() {
8    return stop_requested.load(std::memory_order_acquire);
9}

Use std::atomic_flag when you specifically want test-and-set semantics or need a tiny flag primitive in synchronization code. That is most common in lock implementations, wait-free experiments, or library internals.

In modern C++, readability matters. Most business logic should prefer std::atomic<bool> because the code expresses intent clearly and avoids forcing readers to decode test-and-set behavior.

Common Pitfalls

One common mistake is building a spinlock with atomic_flag when a std::mutex would be safer and more efficient under contention. Spinlocks can be acceptable in very short critical sections on carefully chosen systems, but they are not a general recommendation.

Another mistake is choosing atomic_flag only because it sounds faster. In many applications, the choice that improves correctness and clarity is more valuable than shaving a tiny abstraction cost.

It is also easy to misuse memory ordering. A flag that signals readiness usually needs acquire and release semantics, not relaxed operations pasted in from an unrelated example.

Summary

  • 'std::atomic<bool> is a general atomic boolean with load, store, exchange, and compare-exchange operations.'
  • 'std::atomic_flag is a minimal flag primitive built around test-and-set style synchronization.'
  • 'std::atomic_flag is guaranteed lock-free; std::atomic<bool> is not universally guaranteed to be.'
  • Prefer std::atomic<bool> for clear application-level state flags.
  • Reserve std::atomic_flag for low-level synchronization code that truly needs its specialized behavior.

Course illustration
Course illustration

All Rights Reserved.