What are atomic flags in C++?
Atomic flags in C++ are a type of atomic variable provided by the C++ Standard Library’s <atomic> header. In programming, the term atomic refers to operations that are indivisible and immune to interference from other threads. These flags are designed to implement lock-free synchronization mechanisms, ensuring safe concurrent access to shared data without the risk of data races.
An atomic flag is a simple boolean variable that supports atomic access, meaning that concurrent operations on the flag do not produce data races. The operations on atomic flags are lock-free, eliminating the need for locks or other blocking mechanisms that can cause threads to wait.
The key operations available for atomic flags include:
test_and_set(): This sets the atomic flag totrueand returns its previous value. This operation is atomic, ensuring that only one thread can successfully set the flag.clear(): This sets the atomic flag tofalse. This operation is also atomic and can be used to reset the flag.
In the context of concurrent programming, atomic flags are valuable synchronization primitives. They enable threads to coordinate their activities without the need for explicit locks. For instance, atomic flags are commonly employed in implementing spin locks. In a spin lock, a thread repeatedly checks an atomic flag until it is set by another thread, indicating that a critical section is available for execution.
Code example
Here’s a simple example demonstrating the usage of atomic flags in C++:
#include <iostream>#include <atomic>#include <thread>std::atomic_flag flag = ATOMIC_FLAG_INIT;void worker(){while (flag.test_and_set(std::memory_order_acquire)){// Spin until the flag is cleared.}std::cout << "Critical section entered." << std::endl;// Perform critical section operations...std::cout << "Critical section exited." << std::endl;flag.clear(std::memory_order_release);}int main(){std::thread t1(worker);std::thread t2(worker);// Allow some time for the threads to start.std::this_thread::sleep_for(std::chrono::milliseconds(100));// Set the flag to allow one of the threads to enter the critical section.flag.clear(std::memory_order_release);t1.join();t2.join();return 0;}
Code explanation
-
Lines 1–3: The necessary headers for the code are included:
<iostream>for input/output operations,<atomic>for atomic types and operations, and<thread>for creating and managing threads. -
Line 5: An atomic flag named
flagis declared and initialized with the macroATOMIC_FLAG_INIT. This macro ensures that the flag is initialized to a cleared state. -
Lines 7–21: The
workerfunction represents the code executed by each worker thread. The function uses a spin-lock mechanism to wait until the flag is cleared. It repeatedly callstest_and_set()on the flag withstd::memory_order_acquirememory order, ensuring atomicity and proper synchronization. Once the flag is cleared, it enters the critical section, performs some operations, and then clears the flag usingflag.clear(std::memory_order_release). -
Lines 25–26: Two threads,
t1andt2, are created and assigned theworkerfunction to be executed concurrently. -
Line 29: The main thread pauses for
100milliseconds usingstd::this_thread::sleep_for(). This allows some time for the worker threads to start and begin spinning on the flag. -
Line 32: The main thread clears the flag using
flag.clear(std::memory_order_release). This allows one of the worker threads to exit the spinning loop and enter the critical section. -
Lines 34–35: The main thread waits for the worker threads,
t1andt2, to complete their execution and join the main thread. This ensures the main thread doesn’t exit prematurely before the worker threads finish their work.
Note: Atomic flags provide a lightweight and efficient mechanism for synchronization in concurrent programming. Leveraging them judiciously is crucial for avoiding data races and other synchronization issues. Remember to ensure proper coordination and synchronization between threads when using atomic flags to achieve safe and predictable concurrent behavior.
Free Resources