atomic bool
atomic flag
C++
multithreading
concurrency

difference between standard's atomic bool and atomic flag

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

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.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions