C++ Standard Library<atomic>

In multithreaded programming, data synchronization and thread safety are important issues.

The C++11 standard introduced<atomic>The library provides a set of atomic operations to ensure that access to a single data item is atomic, i.e., indivisible, in a multithreaded environment. This can avoid data races and ensure thread safety.

Atomic operations are operations that cannot be interrupted by other threads during execution.

<atomic>The atomic types in the library provide such operations, which can ensure safe access to shared data in a multithreaded environment.

Syntax

<atomic>The library provides various atomic types, includingatomic<bool>, atomic<char>, atomic<short>, atomic<int>, atomic<long>, atomic<long long>, atomic<wchar_t>, atomic<char16_t>, atomic<char32_t>, atomic<unsigned char>, atomic<unsigned short>, atomic<unsigned>, atomic<unsigned long>, atomic<unsigned long long>, atomic<float>, atomic<double>, atomic<long double>etc.

Basic Operations

  • load(): safely read the value of an atomic variable.
  • store(value): safely write a value to an atomic variable.
  • exchange(value): replace the value of an atomic variable withvalue, and return the old value of the atomic variable.
  • compare_exchange_weak(expected, desired): if the current value of the atomic variable equalsexpected, then set it todesired, and returnstrue. Otherwise, it willexpectedSet to the current value of the atomic variable, and return.false。
  • compare_exchange_strong(expected, desired): andcompare_exchange_weaksimilar, but loops until successful.

Example

The following is an example using<atomic>A simple example of the library, demonstrating how to safely update a shared counter in a multi-threaded environment.

Example

#include <iostream>
#include <atomic>
#include <thread>

std::atomic<int> counter(0); // Initialize atomic counter

void increment() {
    for (int i = 0; i < 10000; ++i) {
        counter.fetch_add(1, std::memory_order_relaxed); // Atomic increment
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Final counter value: " << counter << std::endl; // Output the final counter value

    return 0;
}

Run the above program, you will see output similar to:

Final counter value: 20000

This output shows that the two threads successfully incremented the counter value 10000 times each without data races.

Notes

  • Usage<atomic>When using the library, it is necessary to ensure that all accesses to shared data are through atomic operations to avoid data races.
  • Different atomic operations have different memory order requirements.std::memory_order_relaxedIt is the lowest memory order requirement, but may not guarantee visibility of operations. Choose an appropriate memory order as needed.
  • The performance overhead of atomic operations is usually higher than that of non-atomic operations, so in a single-threaded environment, using ordinary variables may be more efficient.

by using<atomic>With the library, C++ programmers can more easily write thread-safe code while maintaining high performance.

other extensions