std::atomic_flag

From cppreference.com
< cpp‎ | atomic
 
 
 
 
Defined in header <atomic>
class atomic_flag;
(since C++11)

std::atomic_flag is an atomic boolean type. Unlike all specializations of std::atomic, it is guaranteed to be lock-free. Unlike std::atomic<bool>, std::atomic_flag does not provide load or store operations.

Member functions

constructs an atomic_flag
(public member function)
the assignment operator
(public member function)
atomically sets flag to false
(public member function)
atomically sets the flag to true and obtains its previous value
(public member function)
(C++20)
atomically returns the value of the flag
(public member function)
(C++20)
blocks the thread until notified and the atomic value changes
(public member function)
notifies at least one thread waiting on the atomic object
(public member function)
notifies all threads blocked waiting on the atomic object
(public member function)

Example

A spinlock mutex can be implemented in userspace using an atomic_flag

#include <thread>
#include <vector>
#include <iostream>
#include <atomic>
 
std::atomic_flag lock = ATOMIC_FLAG_INIT;
 
void f(int n)
{
    for (int cnt = 0; cnt < 100; ++cnt) {
        while (lock.test_and_set(std::memory_order_acquire))  // acquire lock
             ; // spin
        std::cout << "Output from thread " << n << '\n';
        lock.clear(std::memory_order_release);               // release lock
    }
}
 
int main()
{
    std::vector<std::thread> v;
    for (int n = 0; n < 10; ++n) {
        v.emplace_back(f, n);
    }
    for (auto& t : v) {
        t.join();
    }
}

Output:

Output from thread 2
Output from thread 6
Output from thread 7
...<exactly 1000 lines>...

Starting in C++20, it can be optimized to write atomic_flag value only when there's a chance to acquire lock

#include <thread>
#include <vector>
#include <iostream>
#include <atomic>
 
std::atomic_flag lock = ATOMIC_FLAG_INIT;
 
void f(int n)
{
    for (int cnt = 0; cnt < 100; ++cnt) {
        while (lock.test_and_set(std::memory_order_acquire))  // acquire lock
             while (lock.test(std::memory_order_relaxed))     // test lock
                 ; // spin
        std::cout << "Output from thread " << n << '\n';
        lock.clear(std::memory_order_release);                // release lock
    }
}
 
int main()
{
    std::vector<std::thread> v;
    for (int n = 0; n < 10; ++n) {
        v.emplace_back(f, n);
    }
    for (auto& t : v) {
        t.join();
    }
}

Output:

Output from thread 2
Output from thread 6
Output from thread 7
...<exactly 1000 lines>...

See also

atomically sets the flag to true and returns its previous value
(function)
atomically sets the value of the flag to false
(function)
blocks the thread until notified and the flag changes
(function)
notifies a thread blocked in atomic_flag_wait
(function)
notifies all threads blocked in atomic_flag_wait
(function)
(C++11)(deprecated in C++20)
initializes an std::atomic_flag to false
(macro constant)