CodeNebula
C++20stladvanced

std::atomic::wait / std::atomic::notify_one / std::atomic::notify_all (C++20 Addition)

C++20 · The Big Four · Compiler flag: -std=c++20

Explanation

Extends all `std::atomic` types with efficient blocking wait and notification. `wait(old)` blocks until the atomic value differs from `old`. `notify_one` wakes one waiting thread; `notify_all` wakes all. Replaces busy-wait polling with OS-level efficient waiting.

Real-World Scenario

Implement a producer-consumer queue where the consumer sleeps efficiently until new data is available, avoiding CPU-wasting spin loops.

Quick Snippet

snippet.cpp
#include <atomic>
#include <thread>

std::atomic<int> mailbox{0};

void producer() {
    mailbox.store(42);
    mailbox.notify_one();  // wake consumer
}

void consumer() {
    mailbox.wait(0);       // sleep until mailbox != 0
    int value = mailbox.load();  // 42
}

Full Example

atomic_wait_notify.cpp
// CodeNebula - C++20 Example: std::atomic::wait, notify_one, notify_all
// Compile: g++ -std=c++20 -Wall -Wextra -pthread -o example atomic_wait_notify.cpp

#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
#include <vector>

int main() {
    std::cout << "=== std::atomic wait/notify ===\n";
    std::cout << "(Efficient blocking without spinning or condition_variable)\n\n";

    // atomic::wait(old) blocks until the value differs from old
    // atomic::notify_one() wakes one waiting thread
    // atomic::notify_all() wakes all waiting threads

    std::cout << "--- Basic wait/notify_one ---\n";
    std::atomic<int> value{0};

    std::jthread waiter([&value] {
        std::cout << "Waiter: waiting for value != 0\n";
        value.wait(0);  // Block until value is not 0
        std::cout << "Waiter: woke up, value = " << value.load() << "\n";
    });

    std::this_thread::sleep_for(std::chrono::milliseconds(50));
    std::cout << "Main: setting value to 42\n";
    value.store(42);
    value.notify_one();

    waiter.join();

    std::cout << "\n--- notify_all: waking multiple waiters ---\n";
    std::atomic<int> phase{0};

    auto phase_worker = [&phase](int id) {
        std::cout << "Worker " << id << " waiting for phase 1\n";
        phase.wait(0);
        std::cout << "Worker " << id << " entered phase 1 (value="
                  << phase.load() << ")\n";
    };

    std::vector<std::jthread> workers;
    for (int i = 0; i < 4; ++i) {
        workers.emplace_back(phase_worker, i);
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(50));
    std::cout << "Main: advancing to phase 1\n";
    phase.store(1);
    phase.notify_all();  // Wake ALL waiters

    for (auto& w : workers) w.join();

    std::cout << "\n--- Multi-phase protocol ---\n";
    std::atomic<int> state{0};
    // States: 0=init, 1=data_ready, 2=data_processed, 3=done

    std::jthread producer([&state] {
        std::cout << "Producer: preparing data\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(20));
        state.store(1);
        state.notify_one();

        state.wait(1);  // Wait until consumer processes
        std::cout << "Producer: consumer processed, finalizing\n";
        state.store(3);
        state.notify_one();
    });

    std::jthread consumer([&state] {
        state.wait(0);  // Wait for data_ready
        std::cout << "Consumer: processing data (state="
                  << state.load() << ")\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(20));
        state.store(2);
        state.notify_one();

        state.wait(2);  // Wait for done
        std::cout << "Consumer: done (state=" << state.load() << ")\n";
    });

    producer.join();
    consumer.join();

    std::cout << "\n--- Atomic bool for simple signaling ---\n";
    std::atomic<bool> ready{false};

    std::jthread signal_thread([&ready] {
        std::this_thread::sleep_for(std::chrono::milliseconds(30));
        ready.store(true);
        ready.notify_all();
    });

    ready.wait(false);
    std::cout << "Signal received!\n";

    return 0;
}
Run command
g++ -std=c++20 -Wall -Wextra -pthread -o example atomic_wait_notify.cpp