Operațiuni Atomice Fără Blocare pe Variabile Non-Atomice cu std::atomic_ref în C++20 în C++

Ghid de concurență de înaltă performanță cu std::atomic_ref în C++20: aplicarea operațiunilor atomice sigure pe elemente existente dintr-un vector sau structură fără a impune ca întreaga variabilă să fie de tip std::atomic.

Sintaxă
#include <atomic> | std::atomic_ref<int> ref(valoare); ref.fetch_add(1, std::memory_order_relaxed);

Înainte de C++20, dacă doreați să actualizați concurent un număr dintr-un vector partajat între mai multe fire de execuție, erați forțat să declarați întregul vector ca std::vector<std::atomic<int>>. Această constrângere făcea vectorul ne-copiabil și introducea overhead inutil în etapele mono-thread. Șablonul std::atomic_ref<T> din C++20 permite crearea temporară a unei referințe atomice peste un obiect non-atomic obișnuit, executând operațiuni hardware atomice (Fetch-and-Add, Compare-and-Swap) direct pe adresa de memorie a acestuia.

Incrementare paralelă cu std::atomic_ref peste un vector standard
#include <atomic>
#include <vector>
#include <thread>
#include <print>

int main() {
    // Un vector standard de întregi obișnuiți (non-atomici):
    std::vector<int> contoare(4, 0);

    auto incrementeaza = [&contoare](size_t index) {
        // Creăm o referință atomică temporară peste elementul din vector:
        std::atomic_ref<int> ref(contoare[index]);
        for (int i = 0; i < 100'000; ++i) {
            ref.fetch_add(1, std::memory_order_relaxed);
        }
    };

    // Lansăm două thread-uri concurente care concurează pe contoare[0]:
    std::jthread t1(incrementeaza, 0);
    std::jthread t2(incrementeaza, 0);

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

    std::println("Valoare finala contor[0]: {} (asteptat: 200000)", contoare[0]);
    return 0;
}