名前空間
変種
操作

std::atomic_fetch_add, std::atomic_fetch_add_explicit

提供: cppreference.com
< cpp‎ | atomic
 
 
 
ヘッダ <atomic> で定義
(1)
template< class T >

T atomic_fetch_add( std::atomic<T>* obj,

                    typename std::atomic<T>::difference_type arg ) noexcept;
template< class T >

T atomic_fetch_add( volatile std::atomic<T>* obj,

                    typename std::atomic<T>::difference_type arg ) noexcept;
(2)
template< class T >

T atomic_fetch_add_explicit( std::atomic<T>* obj,
                             typename std::atomic<T>::difference_type arg,

                             std::memory_order order ) noexcept;
template< class T >

T atomic_fetch_add_explicit( volatile std::atomic<T>* obj,
                             typename std::atomic<T>::difference_type arg,

                             std::memory_order order ) noexcept;

アトミック加算を行います。 obj の指す値に arg をアトミックに加算し、 obj がそれまで保持していた値を返します。 この操作は以下のコードが実行されたかのように行われます。

1) obj->fetch_add(arg)
2) obj->fetch_add(arg, order)

目次

[編集] 引数

obj - 変更するアトミックオブジェクトを指すポインタ
arg - アトミックオブジェクトに格納されている値に加算する値
order - この操作に対するメモリ同期順序付け。 すべての値を指定できます。

[編集] 戻り値

*obj変更順序における、この関数の効果の直前の値。

[編集] 実装例

template< class T >
T atomic_fetch_add( std::atomic<T>* obj, typename std::atomic<T>::difference_type arg )
{
    return obj->fetch_add(arg);
}

[編集]

fetch_add を使用して単一ライター/複数リーダーのロックを作ることができます。 この過度に単純化された実装はロックアウトフリーでないことに注意してください。

#include <string>
#include <thread>
#include <vector>
#include <iostream>
#include <atomic>
#include <chrono>
 
// meaning of cnt:
// 5: there are no active readers or writers.
// 1...4: there are 4...1 readers active, The writer is blocked
// 0: temporary value between fetch_sub and fetch_add in reader lock
// -1: there is a writer active. The 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(std::chrono::milliseconds(1));
    }
}
 
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(std::chrono::milliseconds(1));
    }
}
 
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 適用先 発行時の動作 正しい動作
P0558R1 C++11 exact type match required because T is deduced from multiple arguments T is deduced from the atomic argument only

[編集] 関連項目

アトミックオブジェクトに格納されている値に引数の値をアトミックに加算し、以前保持されていた値を取得します
(std::atomicのパブリックメンバ関数) [edit]
アトミックオブジェクトから非アトミック値を減算し、アトミックの以前の値を取得します
(関数テンプレート) [edit]
atomic_fetch_add, atomic_fetch_add_explicitC言語リファレンス