Стандартная библиотека C++<atomic>

В многопоточном программировании синхронизация данных и потокобезопасность являются важными вопросами.

Стандарт C++11 ввёл<atomic>Библиотека предоставляет набор атомарных операций, чтобы гарантировать, что доступ к отдельному элементу данных является атомарным, то есть неделимым, в многопоточной среде. Это позволяет избежать гонок данных и обеспечить потокобезопасность.

Атомарные операции — это операции, которые не могут быть прерваны другими потоками во время выполнения.

<atomic>Атомарные типы в библиотеке предоставляют такие операции, которые могут обеспечить безопасный доступ к общим данным в многопоточной среде.

Синтаксис

<atomic>Библиотека предоставляет различные атомарные типы, включаяatomic<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>и т. д.

Базовые операции

  • load(): безопасно читать значение атомарной переменной.
  • store(value): безопасно записать значение в атомарную переменную.
  • exchange(value): заменить значение атомарной переменной наvalue, и вернуть старое значение атомарной переменной.
  • compare_exchange_weak(expected, desired): если текущее значение атомарной переменной равноexpected, то установить его вdesired, и возвращаетtrue. В противном случае будетexpectedУстановить в текущее значение атомарной переменной и вернуть.false。
  • compare_exchange_strong(expected, desired): иcompare_exchange_weakаналогично, но зацикливается до успешного выполнения.

Пример

Ниже приведён пример использования<atomic>Простой пример библиотеки, демонстрирующий, как безопасно обновлять общий счётчик в многопоточной среде.

Пример

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

std::atomic<int> counter(0); // Инициализация атомарного счётчика

void increment() {
    for (int i = 0; i < 10000; ++i) {
        counter.fetch_add(1, std::memory_order_relaxed); // Атомарный инкремент
    }
}

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

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

    std::cout << "Final counter value: " << counter << std::endl; // Вывод итогового значения счётчика

    return 0;
}

Запустите приведённую выше программу, и вы увидите вывод, подобный следующему:

Final counter value: 20000

Этот вывод показывает, что два потока успешно увеличили значение счётчика по 10000 раз каждый без гонок данных.

Примечания

  • Использование<atomic>При использовании библиотеки необходимо гарантировать, что все обращения к общим данным выполняются через атомарные операции, чтобы избежать гонок данных.
  • Разные атомарные операции имеют разные требования к порядку памяти.std::memory_order_relaxedЭто самое слабое требование к порядку доступа к памяти, но оно может не гарантировать видимость операций. Выберите подходящий порядок доступа к памяти при необходимости.
  • Накладные расходы атомарных операций обычно выше, чем у неатомарных операций, поэтому в однопоточной среде использование обычных переменных может быть более эффективным.

используя<atomic>С этой библиотекой программисты на C++ могут легче писать потокобезопасный код, сохраняя высокую производительность.

Другие расширения