C++11 allows the use of atomics in signal handlers. In C++17 the signal handler feature is further improved. The std::atomic_flag
is an atomic boolean type that is guaranteed to be lock-free and can be used in signal handlers. Moreover, the <csignal>
header in C++ has an integer type std::sig_atomic_t
that can be accessed as an atomic entity even in the presence of asynchronous interrupts made by signals. In this post, we explain how to use atomic_flag
in C++.
What is atomic_flag in C++?
The std::atomic_flag
is a flag in the atomics library which is known as an atomic boolean type. The std::atomic
is guaranteed to be lock-and does not provide load or store operations. In addition, they provide synchronization and order constraints on the program execution.
Here is the general syntax since C++11.
1 2 3 |
std::atomic_flag <flag_name>; |
Here is how we can declare it.
1 2 3 |
std::atomic_flag flag = ATOMIC_FLAG_INIT; |
What are the features of atomic_flag in modern C++?
The std::atomic_flag
has useful features, these are as follows.
The clear()
feature is used to set flags to false atomically, in example we can use it with a memory_order as below,
1 2 3 |
flag.clear(std::memory_order_release); |
test_and_set()
tests the flag to true and obtains its previous value, in example we can use it with a memory_order
in a while loop as we show in the example below:
1 2 3 4 5 |
while (flag.test_and_set(std::memory_order_acquire)) // acquire flag { } |
The test()
feature is new in C++20, returns the value of the flag atomically, like so:
1 2 3 4 5 |
while ( flag.test(std::memory_order_relaxed) ) // release flag { } |
The wait()
feature is new in C++20 and it blocks the thread until the atomic value changes and it is notified. Here is an example:
1 2 3 |
wait ( true, std::memory_order_relaxed); |
in C++20, there are notify_one()
and notify_all()
features too.
Note that, std::atomic_flag
is a pretty low-level type – you can consider using atomic_bool
instead. Also, you can use member functions with the set
and the clear
methods. You can also use higher level constructs, such as a std::mutex
and std:: lock_guard
.
How to use atomic_flag in modern C++?
Here is an atomic_flag
C++ example.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#include <iostream> #include <atomic> #include <thread> #include <vector> #include <sstream> #include <csignal> std::atomic_flag flag = ATOMIC_FLAG_INIT; std::stringstream stream; void myf(int x) { while ( flag.test_and_set() ) {} stream << "This is thread " << x << ","; flag.clear(); } int main () { std::thread t1( &myf, 1 ); std::thread t2( &myf, 2 ); t1.join(); t2.join(); std::cout << stream.str(); system("pause"); return 0; } |
The std::atomic_flag
is an atomic boolean type that is guaranteed to be lock-free and can be used in signal handlers. If you want to use atomics in signal handlers see Allow atomics use in signal handlers Proposal document.
C++ Builder is the easiest and fastest C and C++ IDE for building simple or professional applications on the Windows, MacOS, iOS & Android operating systems. It is also easy for beginners to learn with its wide range of samples, tutorials, help files, and LSP support for code. RAD Studio’s C++ Builder version comes with the award-winning VCL framework for high-performance native Windows apps and the powerful FireMonkey (FMX) framework for cross-platform UIs.
There is a free C++ Builder Community Edition for students, beginners, and startups; it can be downloaded from here. For professional developers, there are Professional, Architect, or Enterprise version.