Стандартная библиотека 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 <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++ могут легче писать потокобезопасный код, сохраняя высокую производительность.