std:: atomic_fetch_add, std:: atomic_fetch_add_explicit
|
Определено в заголовочном файле
<atomic>
|
||
|
template
<
class
T
>
T atomic_fetch_add
(
std::
atomic
<
T
>
*
obj,
|
(1) | (начиная с C++11) |
|
template
<
class
T
>
T atomic_fetch_add
(
volatile
std::
atomic
<
T
>
*
obj,
|
(2) | (начиная с C++11) |
|
template
<
class
T
>
T atomic_fetch_add_explicit
(
std::
atomic
<
T
>
*
obj,
|
(3) | (начиная с C++11) |
|
template
<
class
T
>
T atomic_fetch_add_explicit
(
volatile
std::
atomic
<
T
>
*
obj,
|
(4) | (начиная с C++11) |
Выполняет атомарное сложение. Атомарно добавляет arg к значению, на которое указывает obj и возвращает значение, которое obj содержал ранее. Операция выполняется так, как если бы был выполнен следующий код:
Если
std::atomic<T>
не имеет члена
fetch_add
(этот член предоставляется только для
целочисленных
,
чисел с плавающей запятой
(начиная с C++20)
и
указательных
типов, за исключением
bool
), программа является некорректной.
Содержание |
Параметры
| obj | - | указатель на атомарный объект для модификации |
| arg | - | значение для добавления к значению, хранящемуся в атомарном объекте |
| order | - | порядок синхронизации памяти |
Возвращаемое значение
Значение, непосредственно предшествующее эффектам этой функции в порядке модификации объекта * obj .
Пример
Однописательский/многопоточный читательский замок может быть реализован с помощью
std::atomic_fetch_add
. Обратите внимание, что эта упрощенная реализация не гарантирует отсутствие блокировок.
#include <atomic> #include <chrono> #include <iostream> #include <string> #include <thread> #include <vector> using namespace std::chrono_literals; // meaning of cnt: // 5: readers and writer are in race. There are no active readers or writers. // 4...0: there are 1...5 active readers, The writer is blocked. // -1: writer won the race and readers are blocked. const int N = 5; // four concurrent readers are allowed std::atomic<int> cnt(N); std::vector<int> data; void reader(int id) { for (;;) { // lock while (std::atomic_fetch_sub(&cnt, 1) <= 0) std::atomic_fetch_add(&cnt, 1); // read if (!data.empty()) std::cout << ("reader " + std::to_string(id) + " sees " + std::to_string(*data.rbegin()) + '\n'); if (data.size() == 25) break; // unlock std::atomic_fetch_add(&cnt, 1); // pause std::this_thread::sleep_for(1ms); } } void writer() { for (int n = 0; n < 25; ++n) { // lock while (std::atomic_fetch_sub(&cnt, N + 1) != N) std::atomic_fetch_add(&cnt, N + 1); // write data.push_back(n); std::cout << "writer pushed back " << n << '\n'; // unlock std::atomic_fetch_add(&cnt, N + 1); // pause std::this_thread::sleep_for(1ms); } } int main() { std::vector<std::thread> v; for (int n = 0; n < N; ++n) v.emplace_back(reader, n); v.emplace_back(writer); for (auto& t : v) t.join(); }
Вывод:
writer pushed back 0 reader 2 sees 0 reader 3 sees 0 reader 1 sees 0 <...> reader 2 sees 24 reader 4 sees 24 reader 1 sees 24
Отчёты о дефектах
Следующие отчеты об изменениях в поведении, содержащие описания дефектов, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| P0558R1 | C++11 |
требовалось точное соответствие типов, потому что
T
выводился из нескольких аргументов
|
T
выводится только
из obj |
Смотрите также
|
атомически добавляет аргумент к значению, хранящемуся в атомарном объекте, и получает значение, хранившееся ранее
(публичная функция-член
std::atomic<T>
)
|
|
|
(C++11)
(C++11)
|
вычитает неатомарное значение из атомарного объекта и получает предыдущее значение атомарного объекта
(шаблон функции) |
|
Документация C
для
atomic_fetch_add
,
atomic_fetch_add_explicit
|
|