C++11 并发指南(atomic 类型详解四 C 风格原子操作介绍)

本文介绍C++11中的原子操作,对比了无保护、互斥对象和原子数据类型对共享资源访问的效果,显示原子操作在保证结果正确时性能更优。还详细讲解了<atomic>头文件中std::atomic_flag和std::atomic的构造函数、成员函数等,以及相关C风格API和初始化宏。

所谓的原子操作,取的就是“原子是最小的、不可分割的最小个体”的意义,它表示在多个线程访问同一个全局资源的时候,能够确保所有其他的线程都不在同一时间内访问相同的资源。也就是他确保了在同一时刻只有唯一的线程对这个资源进行访问。这有点类似互斥对象对共享资源的访问的保护,但是原子操作更加接近底层,因而效率更高。

在以往的C++标准中并没有对原子操作进行规定,我们往往是使用汇编语言,或者是借助第三方的线程库,例如intel的pthread来实现。在新标准C++11,引入了原子操作的概念,并通过这个新的头文件提供了多种原子操作数据类型,例如,atomic_bool,atomic_int等等,如果我们在多个线程中对这些类型的共享资源进行操作,编译器将保证这些操作都是原子性的,也就是说,确保任意时刻只有一个线程对这个资源进行访问,编译器将保证,多个线程访问这个共享资源的正确性。从而避免了锁的使用,提高了效率。

我们还是来看一个实际的例子。假若我们要设计一个广告点击统计程序,在服务器程序中,使用多个线程模拟多个用户对广告的点击:

#include <boost/thread/thread.hpp>
#include <atomic>
#include <iostream>
#include <time.h>

using namespace std;
// 全局的结果数据
long total = 0;

// 点击函数
void click()
{
    for(int i=0; i<1000000;++i)
    {
        // 对全局数据进行无锁访问
        total += 1;    
    }
}
 
 
int main(int argc, char* argv[])
{
    // 计时开始
    clock_t start = clock();
    // 创建100个线程模拟点击统计
    boost::thread_group threads;
    for(int i=0; i<100;++i)
    {
        threads.create_thread(click);
    }

    threads.join_all();
    // 计时结束
    clock_t finish = clock();
    // 输出结果
    cout<<"result:"<<total<<endl;
    cout<<"duration:"<<finish -start<<"ms"<<endl;
    return 0;
}

从执行的结果来看,这样的方法虽然非常快,但是结果不正确
E:SourceCodeMinGW>thread.exe
result:87228026
duration:528ms

很自然地,我们会想到使用互斥对象来对全局共享资源的访问进行保护,于是有了下面的实现:

long total = 0;
// 对共享资源进行保护的互斥对象
mutex m;

void click()
{
    for(int i=0; i<1000000;++i)
    {
        // 访问之前,锁定互斥对象
        m.lock();
        total += 1;
        // 访问完成后,释放互斥对象
        m.unlock();
    }
}
互斥对象的使用,保证了同一时刻只有唯一的一个线程对这个共享进行访问,从执行的结果来看,互斥对象保证了结果的正确性,但是也有非常大的性能损失,从刚才的528ms变成了现在的8431,用了原来时间的10多倍的时间。这个损失够大。
E:SourceCodeMinGW>thread.exe
result:100000000
duration:8431ms

如果是在C++11之前,我们的解决方案也就到此为止了,但是,C++对性能的追求是永无止境的,他总是想尽一切办法榨干CPU的性能。在C++11中,实现了原子操作的数据类型(atomic_bool,atomic_int,atomic_long等等),对于这些原子数据类型的共享资源的访问,无需借助mutex等锁机制,也能够实现对共享资源的正确访问。

// 引入原子数据类型的头文件
#include <atomic>
 

// 用原子数据类型作为共享资源的数据类型
atomic_long total(0);
//long total = 0;
 
void click()
{
    for(int i=0; i<1000000;++i)
    {
        // 仅仅是数据类型的不同而以,对其的访问形式与普通数据类型的资源并无区别
        total += 1;
    }
}

我们来看看使用原子数据类型之后的效果如何:
E:SourceCodeMinGW>thread.exe
result:100000000
duration:2105ms

结果正确!耗时只是使用mutex互斥对象的四分之一!也仅仅是不采用任何保护机制的时间的4倍。可以说这是一个非常不错的成绩了。

原子操作的实现跟普通数据类型类似,但是它能够在保证结果正确的前提下,提供比mutex等锁机制更好的性能,如果我们要访问的共享资源可以用原子数据类型表示,那么在多线程程序中使用这种新的等价数据类型,是一个不错的选择。

 

 

C++11 并发指南已经写了 5 章,前五章重点介绍了多线程编程方面的内容,但大部分内容只涉及多线程、互斥量、条件变量和异步编程相关的 API,C++11 程序员完全可以不必知道这些 API 在底层是如何实现的,只需要清楚 C++11 多线程和异步编程相关 API 的语义,然后熟加练习即可应付大部分多线程编码需求。但是在很多极端的场合下为了性能和效率,我们需要开发一些 lock-free 的算法和数据结构,前面几章的内容可能就派不上用场了,因此从本文开始介绍 C++11 标准中 <atomic> 头文件里面的类和相关函数。

本文介绍 <atomic> 头文件中最简单的原子类型: atomic_flag。atomic_flag 一种简单的原子布尔类型,只支持两种操作,test-and-set 和 clear。

std::atomic_flag 构造函数

std::atomic_flag 构造函数如下:

  • atomic_flag() noexcept = default;
  • atomic_flag (const atomic_flag&T) = delete;

std::atomic_flag 只有默认构造函数,拷贝构造函数已被禁用,因此不能从其他的 std::atomic_flag 对象构造一个新的 std::atomic_flag 对象。

如果在初始化时没有明确使用 ATOMIC_FLAG_INIT初始化,那么新创建的 std::atomic_flag 对象的状态是未指定的(unspecified)(既没有被 set 也没有被 clear。)另外,atomic_flag不能被拷贝,也不能 move 赋值。

ATOMIC_FLAG_INIT: 如果某个 std::atomic_flag 对象使用该宏初始化,那么可以保证该 std::atomic_flag 对象在创建时处于 clear 状态。

下面先看一个简单的例子,main() 函数中创建了 10 个线程进行计数,率先完成计数任务的线程输出自己的 ID,后续完成计数任务的线程不会输出自身 ID:

复制代码
#include <iostream>              // std::cout
#include <atomic>                // std::atomic, std::atomic_flag, ATOMIC_FLAG_INIT
#include <thread>                // std::thread, std::this_thread::yield
#include <vector>                // std::vector

std::atomic<bool> ready(false);    // can be checked without being set
std::atomic_flag winner = ATOMIC_FLAG_INIT;    // always set when checked

void count1m(int id)
{
    while (!ready) {
        std::this_thread::yield();
    } // 等待主线程中设置 ready 为 true.

    for (int i = 0; i < 1000000; ++i) {
    } // 计数.

    // 如果某个线程率先执行完上面的计数过程,则输出自己的 ID.
    // 此后其他线程执行 test_and_set 是 if 语句判断为 false,
    // 因此不会输出自身 ID.
    if (!winner.test_and_set()) {
        std::cout << "thread #" << id << " won!\n";
    }
};

int main()
{
    std::vector<std::thread> threads;
    std::cout << "spawning 10 threads that count to 1 million...\n";
    for (int i = 1; i <= 10; ++i)
        threads.push_back(std::thread(count1m, i));
    ready = true;

    for (auto & th:threads)
        th.join();

    return 0;
}
复制代码

多次执行结果如下:

复制代码
atomic ) ./Atomic-Flag1 
spawning 10 threads that count to 1 million...
thread #6 won!
atomic ) ./Atomic-Flag1 
spawning 10 threads that count to 1 million...
thread #1 won!
atomic ) ./Atomic-Flag1 
spawning 10 threads that count to 1 million...
thread #5 won!
atomic ) ./Atomic-Flag1 
spawning 10 threads that count to 1 million...
thread #1 won!
atomic ) ./Atomic-Flag1 
spawning 10 threads that count to 1 million...
thread #1 won!
atomic ) ./Atomic-Flag1 
spawning 10 threads that count to 1 million...
thread #10 won!
复制代码

std::atomic_flag::test_and_set 介绍

std::atomic_flag 的 test_and_set 函数原型如下:

bool test_and_set (memory_order sync = memory_order_seq_cst) volatile noexcept;
bool test_and_set (memory_order sync = memory_order_seq_cst) noexcept;

test_and_set() 函数检查 std::atomic_flag 标志,如果 std::atomic_flag 之前没有被设置过,则设置 std::atomic_flag 的标志,并返回先前该 std::atomic_flag 对象是否被设置过,如果之前 std::atomic_flag 对象已被设置,则返回 true,否则返回 false。

test-and-set 操作是原子的(因此 test-and-set 是原子 read-modify-write (RMW)操作)。

test_and_set 可以指定 Memory Order(后续的文章会详细介绍 C++11 的 Memory Order,此处为了完整性列出 test_and_set 参数 sync 的取值),取值如下:

 

Memory Order 值 Memory Order 类型
memory_order_relaxed Relaxed
memory_order_consume Consume
memory_order_acquire Acquire
memory_order_release Release
memory_order_acq_rel Acquire/Release
memory_order_seq_cst Sequentially consistent

 一个简单的例子:

复制代码
#include <iostream>                // std::cout
#include <atomic>                // std::atomic_flag
#include <thread>                // std::thread
#include <vector>                // std::vector
#include <sstream>                // std::stringstream

std::atomic_flag lock_stream = ATOMIC_FLAG_INIT;
std::stringstream stream;

void append_number(int x)
{
    while (lock_stream.test_and_set()) {
    }
    stream << "thread #" << x << '\n';
    lock_stream.clear();
}

int main()
{
    std::vector < std::thread > threads;
    for (int i = 1; i <= 10; ++i)
        threads.push_back(std::thread(append_number, i));
    for (auto & th:threads)
        th.join();

    std::cout << stream.str() << std::endl;;
    return 0;
}
复制代码

执行结果如下:

复制代码
thread #1
thread #2
thread #3
thread #4
thread #5
thread #6
thread #7
thread #8
thread #9
thread #10
复制代码

std::atomic_flag::clear() 介绍

清除 std::atomic_flag 对象的标志位,即设置 atomic_flag 的值为 false。clear 函数原型如下:

void clear (memory_order sync = memory_order_seq_cst) volatile noexcept;
void clear (memory_order sync = memory_order_seq_cst) noexcept;

清除 std::atomic_flag 标志使得下一次调用 std::atomic_flag::test_and_set 返回 false。

std::atomic_flag::clear() 可以指定 Memory Order(后续的文章会详细介绍 C++11 的 Memory Order,此处为了完整性列出 clear 参数 sync 的取值),取值如下:

 

Memory Order 值 Memory Order 类型
memory_order_relaxed Relaxed
memory_order_consume Consume
memory_order_acquire Acquire
memory_order_release Release
memory_order_acq_rel Acquire/Release
memory_order_seq_cst Sequentially consistent

结合 std::atomic_flag::test_and_set() 和 std::atomic_flag::clear(),std::atomic_flag 对象可以当作一个简单的自旋锁使用,请看下例:

复制代码
#include <thread>
#include <vector>
#include <iostream>
#include <atomic>

std::atomic_flag lock = ATOMIC_FLAG_INIT;

void f(int n)
{
    for (int cnt = 0; cnt < 100; ++cnt) {
        while (lock.test_and_set(std::memory_order_acquire))  // acquire lock
             ; // spin
        std::cout << "Output from thread " << n << '\n';
        lock.clear(std::memory_order_release);               // release lock
    }
}

int main()
{
    std::vector<std::thread> v;
    for (int n = 0; n < 10; ++n) {
        v.emplace_back(f, n);
    }
    for (auto& t : v) {
        t.join();
    }
}
复制代码

在上面的程序中,std::atomic_flag 对象 lock 的上锁操作可以理解为 lock.test_and_set(std::memory_order_acquire); (此处指定了 Memory Order,更多有关 Memory Order 的概念,我会在后续的文章中介绍),解锁操作相当与 lock.clear(std::memory_order_release)。

在上锁的时候,如果 lock.test_and_set 返回 false,则表示上锁成功(此时 while 不会进入自旋状态),因为此前 lock 的标志位为 false(即没有线程对 lock 进行上锁操作),但调用 test_and_set 后 lock 的标志位为 true,说明某一线程已经成功获得了 lock 锁。

如果在该线程解锁(即调用 lock.clear(std::memory_order_release)) 之前,另外一个线程也调用 lock.test_and_set(std::memory_order_acquire) 试图获得锁,则 test_and_set(std::memory_order_acquire) 返回 true,则 while 进入自旋状态。如果获得锁的线程解锁(即调用了 lock.clear(std::memory_order_release))之后,某个线程试图调用 lock.test_and_set(std::memory_order_acquire) 并且返回 false,则 while 不会进入自旋,此时表明该线程成功地获得了锁。

按照上面的分析,我们知道在某种情况下 std::atomic_flag 对象可以当作一个简单的自旋锁使用。

 

 C++11 中最简单的原子类型 std::atomic_flag,但是 std::atomic_flag 过于简单,只提供了 test_and_set 和 clear 两个 API,不能满足其他需求(如 store, load, exchange, compare_exchange 等),因此本文将介绍功能更加完善的 std::atomic 类。

std::atomic 基本介绍

std::atomic 是模板类,一个模板类型为 T 的原子对象中封装了一个类型为 T 的值。

template <class T> struct atomic;

原子类型对象的主要特点就是从不同线程访问不会导致数据竞争(data race)。因此从不同线程访问某个原子对象是良性 (well-defined) 行为,而通常对于非原子类型而言,并发访问某个对象(如果不做任何同步操作)会导致未定义 (undifined) 行为发生。

C++11 标准中的基本 std::atomic 模板定义如下:

复制代码
template < class T > struct atomic {
    bool is_lock_free() const volatile;
    bool is_lock_free() const;
    void store(T, memory_order = memory_order_seq_cst) volatile;
    void store(T, memory_order = memory_order_seq_cst);
    T load(memory_order = memory_order_seq_cst) const volatile;
    T load(memory_order = memory_order_seq_cst) const;
    operator  T() const volatile;
    operator  T() const;
    T exchange(T, memory_order = memory_order_seq_cst) volatile;
    T exchange(T, memory_order = memory_order_seq_cst);
    bool compare_exchange_weak(T &, T, memory_order, memory_order) volatile;
    bool compare_exchange_weak(T &, T, memory_order, memory_order);
    bool compare_exchange_strong(T &, T, memory_order, memory_order) volatile;
    bool compare_exchange_strong(T &, T, memory_order, memory_order);
    bool compare_exchange_weak(T &, T, memory_order = memory_order_seq_cst) volatile;
    bool compare_exchange_weak(T &, T, memory_order = memory_order_seq_cst);
    bool compare_exchange_strong(T &, T, memory_order = memory_order_seq_cst) volatile;
    bool compare_exchange_strong(T &, T, memory_order = memory_order_seq_cst);
    atomic() = default;
    constexpr atomic(T);
    atomic(const atomic &) = delete;
    atomic & operator=(const atomic &) = delete;
    atomic & operator=(const atomic &) volatile = delete;
    T operator=(T) volatile;
    T operator=(T);
};
复制代码

另外,C++11 标准库 std::atomic 提供了针对整形(integral)和指针类型的特化实现,分别定义如下:

针对整形(integal)的特化,其中 integal 代表了如下类型char, signed char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long, char16_t, char32_t, wchar_t:

template   <> struct   atomic<integral> {
     bool   is_lock_free() const   volatile ;
     bool   is_lock_free() const ;
 
     void   store(integral, memory_order = memory_order_seq_cst) volatile ;
     void   store(integral, memory_order = memory_order_seq_cst);
 
     integral load(memory_order = memory_order_seq_cst) const   volatile ;
     integral load(memory_order = memory_order_seq_cst) const ;
 
     operator integral() const   volatile ;
     operator integral() const ;
 
     integral exchange(integral, memory_order = memory_order_seq_cst) volatile ;
     integral exchange(integral, memory_order = memory_order_seq_cst);
 
     bool   compare_exchange_weak(integral&, integral, memory_order, memory_order) volatile ;
     bool   compare_exchange_weak(integral&, integral, memory_order, memory_order);
 
     bool   compare_exchange_strong(integral&, integral, memory_order, memory_order) volatile ;
     bool   compare_exchange_strong(integral&, integral, memory_order, memory_order);
 
     bool   compare_exchange_weak(integral&, integral, memory_order = memory_order_seq_cst) volatile ;
     bool   compare_exchange_weak(integral&, integral, memory_order = memory_order_seq_cst);
 
     bool   compare_exchange_strong(integral&, integral, memory_order = memory_order_seq_cst) volatile ;
     bool   compare_exchange_strong(integral&, integral, memory_order = memory_order_seq_cst);
 
     integral fetch_add(integral, memory_order = memory_order_seq_cst) volatile ;
     integral fetch_add(integral, memory_order = memory_order_seq_cst);
 
     integral fetch_sub(integral, memory_order = memory_order_seq_cst) volatile ;
     integral fetch_sub(integral, memory_order = memory_order_seq_cst);
 
     integral fetch_and(integral, memory_order = memory_order_seq_cst) volatile ;
     integral fetch_and(integral, memory_order = memory_order_seq_cst);
 
     integral fetch_or(integral, memory_order = memory_order_seq_cst) volatile ;
     integral fetch_or(integral, memory_order = memory_order_seq_cst);
 
     integral fetch_xor(integral, memory_order = memory_order_seq_cst) volatile ;
     integral fetch_xor(integral, memory_order = memory_order_seq_cst);
     
     atomic() = default ;
     constexpr   atomic(integral);
     atomic( const   atomic&) = delete ;
 
     atomic& operator=( const   atomic&) = delete ;
     atomic& operator=( const   atomic&) volatile   = delete ;
     
     integral operator=(integral) volatile ;
     integral operator=(integral);
     
     integral operator++( int ) volatile ;
     integral operator++( int );
     integral operator--( int ) volatile ;
     integral operator--( int );
     integral operator++() volatile ;
     integral operator++();
     integral operator--() volatile ;
     integral operator--();
     integral operator+=(integral) volatile ;
     integral operator+=(integral);
     integral operator-=(integral) volatile ;
     integral operator-=(integral);
     integral operator&=(integral) volatile ;
     integral operator&=(integral);
     integral operator|=(integral) volatile ;
     integral operator|=(integral);
     integral operator^=(integral) volatile ;
     integral operator^=(integral);
};

针对指针的特化:

template   < class   T> struct   atomic<T*> {
     bool   is_lock_free() const   volatile ;
     bool   is_lock_free() const ;
 
     void   store(T*, memory_order = memory_order_seq_cst) volatile ;
     void   store(T*, memory_order = memory_order_seq_cst);
 
     T* load(memory_order = memory_order_seq_cst) const   volatile ;
     T* load(memory_order = memory_order_seq_cst) const ;
 
     operator T*() const   volatile ;
     operator T*() const ;
 
     T* exchange(T*, memory_order = memory_order_seq_cst) volatile ;
     T* exchange(T*, memory_order = memory_order_seq_cst);
 
     bool   compare_exchange_weak(T*&, T*, memory_order, memory_order) volatile ;
     bool   compare_exchange_weak(T*&, T*, memory_order, memory_order);
 
     bool   compare_exchange_strong(T*&, T*, memory_order, memory_order) volatile ;
     bool   compare_exchange_strong(T*&, T*, memory_order, memory_order);
 
     bool   compare_exchange_weak(T*&, T*, memory_order = memory_order_seq_cst) volatile ;
     bool   compare_exchange_weak(T*&, T*, memory_order = memory_order_seq_cst);
 
     bool   compare_exchange_strong(T*&, T*, memory_order = memory_order_seq_cst) volatile ;
     bool   compare_exchange_strong(T*&, T*, memory_order = memory_order_seq_cst);
 
     T* fetch_add( ptrdiff_t , memory_order = memory_order_seq_cst) volatile ;
     T* fetch_add( ptrdiff_t , memory_order = memory_order_seq_cst);
 
     T* fetch_sub( ptrdiff_t , memory_order = memory_order_seq_cst) volatile ;
     T* fetch_sub( ptrdiff_t , memory_order = memory_order_seq_cst);
 
     atomic() = default ;
     constexpr   atomic(T*);
     atomic( const   atomic&) = delete ;
 
     atomic& operator=( const   atomic&) = delete ;
     atomic& operator=( const   atomic&) volatile   = delete ;
 
     T* operator=(T*) volatile ;
     T* operator=(T*);
     T* operator++( int ) volatile ;
     T* operator++( int );
     T* operator--( int ) volatile ;
     T* operator--( int );
     T* operator++() volatile ;
     T* operator++();
     T* operator--() volatile ;
     T* operator--();
     T* operator+=( ptrdiff_t ) volatile ;
     T* operator+=( ptrdiff_t );
     T* operator-=( ptrdiff_t ) volatile ;
     T* operator-=( ptrdiff_t );
};

std::atomic 成员函数

 好了,对 std::atomic 有了一个最基本认识之后我们来看 std::atomic 的成员函数吧。

std::atomic 构造函数

std::atomic 的构造函数如下:

default (1)
          atomic() noexcept = default;
initialization (2)
constexpr atomic (T val) noexcept;
copy [deleted] (3)
          atomic (const atomic&) = delete;

  1. 默认构造函数,由默认构造函数创建的 std::atomic 对象处于未初始化(uninitialized)状态,对处于未初始化(uninitialized)状态 std::atomic对象可以由 atomic_init 函数进行初始化。
  2. 初始化构造函数,由类型 T初始化一个 std::atomic对象。
  3. 拷贝构造函数被禁用。

请看下例:

#include <iostream>       // std::cout
#include <atomic>         // std::atomic, std::atomic_flag, ATOMIC_FLAG_INIT
#include <thread>         // std::thread, std::this_thread::yield
#include <vector>         // std::vector
 
// 由 false 初始化一个 std::atomic<bool> 类型的原子变量
std::atomic< bool > ready( false );
std::atomic_flag winner = ATOMIC_FLAG_INIT;
 
void   do_count1m( int   id)
{
     while   (!ready) { std::this_thread::yield(); } // 等待 ready 变为 true.
 
     for   ( volatile   int   i=0; i<1000000; ++i) {} // 计数
 
     if   (!winner.test_and_set()) {
       std::cout << "thread #"   << id << " won!\n" ;
     }
}
 
int   main ()
{
     std::vector<std:: thread > threads;
     std::cout << "spawning 10 threads that count to 1 million...\n" ;
     for   ( int   i=1; i<=10; ++i) threads.push_back(std:: thread (count1m,i));
     ready = true ;
 
     for   ( auto & th : threads) th.join();
     return   0;
}
std::atomic::operator=() 函数

std::atomic 的赋值操作函数定义如下:

set value (1)
T operator= (T val) noexcept;
T operator= (T val) volatile noexcept;
copy [deleted] (2)
atomic& operator= (const atomic&) = delete;
atomic& operator= (const atomic&) volatile = delete;

可以看出,普通的赋值拷贝操作已经被禁用。但是一个类型为 T 的变量可以赋值给相应的原子类型变量(相当与隐式转换),该操作是原子的,内存序(Memory Order) 默认为顺序一致性(std::memory_order_seq_cst),如果需要指定其他的内存序,需使用 std::atomic::store()。

#include <iostream>             // std::cout
#include <atomic>               // std::atomic
#include <thread>               // std::thread, std::this_thread::yield
 
std::atomic < int > foo = 0;
 
void   set_foo( int   x)
{
     foo = x; // 调用 std::atomic::operator=().
}
 
void   print_foo()
{
     while   (foo == 0) { // wait while foo == 0
         std::this_thread::yield();
     }
     std::cout << "foo: "   << foo << '\n' ;
}
 
int   main()
{
     std:: thread   first(print_foo);
     std:: thread   second(set_foo, 10);
     first.join();
     second.join();
     return   0;
}
基本 std::atomic 类型操作

本节主要介绍基本 std::atomic 类型所具备的操作(即成员函数)。我们知道 std::atomic 是模板类,一个模板类型为 T 的原子对象中封装了一个类型为 T 的值。本文<std::atomic 基本介绍>一节中也提到了 std::atomic 类模板除了基本类型以外,还针对整形和指针类型做了特化。 特化的 std::atomic 类型支持更多的操作,如 fetch_add, fetch_sub, fetch_and 等。本小节介绍基本 std::atomic 类型所具备的操作:

bool   is_lock_free() const   volatile   noexcept ;
bool   is_lock_free() const   noexcept ;
void   store (T val, memory_order sync = memory_order_seq_cst) volatile   noexcept ;
void   store (T val, memory_order sync = memory_order_seq_cst) noexcept ;

Memory Order 值 Memory Order 类型
memory_order_relaxed Relaxed
memory_order_release Release
memory_order_seq_cst Sequentially consistent

#include <iostream>       // std::cout
#include <atomic>         // std::atomic, std::memory_order_relaxed
#include <thread>         // std::thread
 
std::atomic< int > foo(0); // 全局的原子对象 foo
 
void   set_foo( int   x)
{
     foo.store(x, std::memory_order_relaxed); // 设置(store) 原子对象 foo 的值
}
 
void   print_foo()
{
     int   x;
     do   {
         x = foo.load(std::memory_order_relaxed); // 读取(load) 原子对象 foo 的值
     } while   (x == 0);
     std::cout << "foo: "   << x << '\n' ;
}
 
int   main ()
{
     std:: thread   first(print_foo); // 线程 first 打印 foo 的值
     std:: thread   second(set_foo, 10); // 线程 second 设置 foo 的值
     first.join();
     second.join();
     return   0;
}
T load (memory_order sync = memory_order_seq_cst) const   volatile   noexcept ;
T load (memory_order sync = memory_order_seq_cst) const   noexcept ;

Memory Order 值 Memory Order 类型
memory_order_relaxed Relaxed
memory_order_consume Consume
memory_order_acquire Acquire
memory_order_seq_cst Sequentially consistent

#include <iostream>       // std::cout
#include <atomic>         // std::atomic, std::memory_order_relaxed
#include <thread>         // std::thread
 
std::atomic< int > foo(0); // 全局的原子对象 foo
 
void   set_foo( int   x)
{
     foo.store(x, std::memory_order_relaxed); // 设置(store) 原子对象 foo 的值
}
 
void   print_foo()
{
     int   x;
     do   {
         x = foo.load(std::memory_order_relaxed); // 读取(load) 原子对象 foo 的值
     } while   (x == 0);
     std::cout << "foo: "   << x << '\n' ;
}
 
int   main ()
{
     std:: thread   first(print_foo); // 线程 first 打印 foo 的值
     std:: thread   second(set_foo, 10); // 线程 second 设置 foo 的值
     first.join();
     second.join();
     return   0;
}
operator T() const   volatile   noexcept ;
operator T() const   noexcept ;
#include <iostream>       // std::cout
#include <atomic>         // std::atomic
#include <thread>         // std::thread, std::this_thread::yield
 
std::atomic< int > foo = 0;
std::atomic< int > bar = 0;
 
void   set_foo( int   x)
{
     foo = x;
}
 
void   copy_foo_to_bar()
{
 
     // 如果 foo == 0,则该线程 yield,
     // 在 foo == 0 时, 实际也是隐含了类型转换操作,
     // 因此也包含了 operator T() const 的调用.
     while   (foo == 0) std::this_thread::yield();
 
     // 实际调用了 operator T() const, 将foo 强制转换成 int 类型,
     // 然后调用 operator=().
     bar = static_cast < int >(foo);
}
 
void   print_bar()
{
     // 如果 bar == 0,则该线程 yield,
     // 在 bar == 0 时, 实际也是隐含了类型转换操作,
     // 因此也包含了 operator T() const 的调用.
     while   (bar == 0) std::this_thread::yield();
     std::cout << "bar: "   << bar << '\n' ;
}
 
int   main ()
{
     std:: thread   first(print_bar);
     std:: thread   second(set_foo, 10);
     std:: thread   third(copy_foo_to_bar);
 
     first.join();
     second.join();
     third.join();
     return   0;
}

 

T exchange (T val, memory_order sync = memory_order_seq_cst) volatile noexcept;
T exchange (T val, memory_order sync = memory_order_seq_cst) noexcept;

Memory Order 值 Memory Order 类型
memory_order_relaxed Relaxed
memory_order_consume Consume
memory_order_acquire Acquire
memory_order_release Release
memory_order_acq_rel Acquire/Release
memory_order_seq_cst Sequentially consistent

请看下面例子,各个线程计数至 1M,首先完成计数任务的线程打印自己的 ID,

#include <iostream>       // std::cout
#include <atomic>         // std::atomic
#include <thread>         // std::thread
#include <vector>         // std::vector
 
std::atomic< bool > ready( false );
std::atomic< bool > winner( false );
 
void   count1m ( int   id)
{
     while   (!ready) {}                  // wait for the ready signal
     for   ( int   i = 0; i < 1000000; ++i) {}   // go!, count to 1 million
     if   (!winner.exchange( true )) { std::cout << "thread #"   << id << " won!\n" ; }
};
 
int   main ()
{
     std::vector<std:: thread > threads;
     std::cout << "spawning 10 threads that count to 1 million...\n" ;
     for   ( int   i = 1; i <= 10; ++i) threads.push_back(std:: thread (count1m,i));
     ready = true ;
     for   ( auto & th : threads) th.join();
 
     return   0;
}

(1)
bool compare_exchange_weak (T& expected, T val,
           memory_order sync = memory_order_seq_cst) volatile noexcept;
bool compare_exchange_weak (T& expected, T val,
           memory_order sync = memory_order_seq_cst) noexcept;
(2)
bool compare_exchange_weak (T& expected, T val,
           memory_order success, memory_order failure) volatile noexcept;
bool compare_exchange_weak (T& expected, T val,
           memory_order success, memory_order failure) noexcept;

  • 相等,则用 val 替换原子对象的旧值。
  • 不相等,则用原子对象的旧值替换 expected ,因此调用该函数之后,如果被该原子对象封装的值与参数 expected 所指定的值不相等,expected 中的内容就是原子对象的旧值。

Memory Order 值 Memory Order 类型
memory_order_relaxed Relaxed
memory_order_consume Consume
memory_order_acquire Acquire
memory_order_release Release
memory_order_acq_rel Acquire/Release
memory_order_seq_cst Sequentially consistent

#include <iostream>       // std::cout
#include <atomic>         // std::atomic
#include <thread>         // std::thread
#include <vector>         // std::vector
 
// a simple global linked list:
struct   Node { int   value; Node* next; };
std::atomic<Node*> list_head( nullptr );
 
void   append( int   val)
{
     // append an element to the list
     Node* newNode = new   Node{val, list_head};
 
     // next is the same as: list_head = newNode, but in a thread-safe way:
     while   (!list_head.compare_exchange_weak(newNode->next,newNode)) {}
     // (with newNode->next updated accordingly if some other thread just appended another node)
}
 
int   main ()
{
     // spawn 10 threads to fill the linked list:
     std::vector<std:: thread > threads;
     for   ( int   i = 0; i < 10; ++i) threads.push_back(std:: thread (append, i));
     for   ( auto & th : threads) th.join();
 
     // print contents:
     for   (Node* it = list_head; it!= nullptr ; it=it->next)
         std::cout << ' '   << it->value;
 
     std::cout << '\n' ;
 
     // cleanup:
     Node* it; while   (it=list_head) {list_head=it->next; delete   it;}
 
     return   0;
}
9 8 7 6 5 4 3 2 1 0

 

(1)
bool compare_exchange_strong (T& expected, T val,
           memory_order sync = memory_order_seq_cst) volatile noexcept;
bool compare_exchange_strong (T& expected, T val,
           memory_order sync = memory_order_seq_cst) noexcept;
(2)
bool compare_exchange_strong (T& expected, T val,
           memory_order success, memory_order failure) volatile noexcept;
bool compare_exchange_strong (T& expected, T val,
           memory_order success, memory_order failure) noexcept;

  • 相等,则用 val 替换原子对象的旧值。
  • 不相等,则用原子对象的旧值替换 expected ,因此调用该函数之后,如果被该原子对象封装的值与参数 expected 所指定的值不相等,expected 中的内容就是原子对象的旧值。

Memory Order 值 Memory Order 类型
memory_order_relaxed Relaxed
memory_order_consume Consume
memory_order_acquire Acquire
memory_order_release Release
memory_order_acq_rel Acquire/Release
memory_order_seq_cst Sequentially consistent

#include <iostream>       // std::cout
#include <atomic>         // std::atomic
#include <thread>         // std::thread
#include <vector>         // std::vector
 
// a simple global linked list:
struct   Node { int   value; Node* next; };
std::atomic<Node*> list_head( nullptr );
 
void   append( int   val)
{
     // append an element to the list
     Node* newNode = new   Node{val, list_head};
 
     // next is the same as: list_head = newNode, but in a thread-safe way:
 
     while   (!(list_head.compare_exchange_strong(newNode->next, newNode)));
     // (with newNode->next updated accordingly if some other thread just appended another node)
}
 
int   main ()
{
     // spawn 10 threads to fill the linked list:
     std::vector<std:: thread > threads;
     for   ( int   i = 0; i < 10; ++i) threads.push_back(std:: thread (append, i));
     for   ( auto & th : threads) th.join();
 
     // print contents:
     for   (Node* it = list_head; it!= nullptr ; it=it->next)
         std::cout << ' '   << it->value;
 
     std::cout << '\n' ;
 
     // cleanup:
     Node* it; while   (it=list_head) {list_head=it->next; delete   it;}
 
     return   0;
}


好了,本文花了大量的篇幅介绍 std::atomic 基本类型,下一篇博客我会给大家介绍 C++11 的标准库中std::atomic 针对整形(integral)和指针类型的特化版本做了哪些改进。

 

 

基本的原子类型 std::atomic 的用法,本节我会给大家介绍C++11 标准库中的 std::atomic 针对整形(integral)和指针类型的特化版本做了哪些改进。

总地来说,C++11 标准库中的 std::atomic 针对整形(integral)和指针类型的特化版本新增了一些算术运算和逻辑运算操作。具体如下:

integral fetch_add(integral, memory_order = memory_order_seq_cst) volatile ;
integral fetch_add(integral, memory_order = memory_order_seq_cst);
integral fetch_sub(integral, memory_order = memory_order_seq_cst) volatile ;
integral fetch_sub(integral, memory_order = memory_order_seq_cst);
integral fetch_and(integral, memory_order = memory_order_seq_cst) volatile ;
integral fetch_and(integral, memory_order = memory_order_seq_cst);
integral fetch_or(integral, memory_order = memory_order_seq_cst) volatile ;
integral fetch_or(integral, memory_order = memory_order_seq_cst);
integral fetch_xor(integral, memory_order = memory_order_seq_cst) volatile ;
integral fetch_xor(integral, memory_order = memory_order_seq_cst);
 
integral operator++( int ) volatile ;
integral operator++( int );
integral operator--( int ) volatile ;
integral operator--( int );
integral operator++() volatile ;
integral operator++();
integral operator--() volatile ;
integral operator--();
integral operator+=(integral) volatile ;
integral operator+=(integral);
integral operator-=(integral) volatile ;
integral operator-=(integral);
integral operator&=(integral) volatile ;
integral operator&=(integral);
integral operator|=(integral) volatile ;
integral operator|=(integral);
integral operator^=(integral) volatile ;
integral operator^=(integral);

 下面我们来简单介绍以上的 std::atomic 特化版本的成员函数。

if T is integral (1)
T fetch_add (T val, memory_order sync = memory_order_seq_cst) volatile noexcept;
T fetch_add (T val, memory_order sync = memory_order_seq_cst) noexcept;
if T is pointer (2)
T fetch_add (ptrdiff_t val, memory_order sync = memory_order_seq_cst) volatile noexcept;
T fetch_add (ptrdiff_t val, memory_order sync = memory_order_seq_cst) noexcept;

Memory Order 值 Memory Order 类型
memory_order_relaxed Relaxed
memory_order_consume Consume
memory_order_acquire Acquire
memory_order_release Release
memory_order_acq_rel Acquire/Release
memory_order_seq_cst Sequentially consistent

if T is integral (1)
T fetch_sub (T val, memory_order sync = memory_order_seq_cst) volatile noexcept;
T fetch_sub (T val, memory_order sync = memory_order_seq_cst) noexcept;
if T is pointer (2)
T fetch_sub (ptrdiff_t val, memory_order sync = memory_order_seq_cst) volatile noexcept;
T fetch_sub (ptrdiff_t val, memory_order sync = memory_order_seq_cst) noexcept;

Memory Order 值 Memory Order 类型
memory_order_relaxed Relaxed
memory_order_consume Consume
memory_order_acquire Acquire
memory_order_release Release
memory_order_acq_rel Acquire/Release
memory_order_seq_cst Sequentially consistent

T fetch_and (T val, memory_order sync = memory_order_seq_cst) volatile   noexcept ;
T fetch_and (T val, memory_order sync = memory_order_seq_cst) noexcept ;

 

Memory Order 值 Memory Order 类型
memory_order_relaxed Relaxed
memory_order_consume Consume
memory_order_acquire Acquire
memory_order_release Release
memory_order_acq_rel Acquire/Release
memory_order_seq_cst Sequentially consistent

T fetch_or (T val, memory_order sync = memory_order_seq_cst) volatile   noexcept ;
T fetch_or (T val, memory_order sync = memory_order_seq_cst) noexcept ;

 

Memory Order 值 Memory Order 类型
memory_order_relaxed Relaxed
memory_order_consume Consume
memory_order_acquire Acquire
memory_order_release Release
memory_order_acq_rel Acquire/Release
memory_order_seq_cst Sequentially consistent

T fetch_xor (T val, memory_order sync = memory_order_seq_cst) volatile   noexcept ;
T fetch_xor (T val, memory_order sync = memory_order_seq_cst) noexcept ;

Memory Order 值 Memory Order 类型
memory_order_relaxed Relaxed
memory_order_consume Consume
memory_order_acquire Acquire
memory_order_release Release
memory_order_acq_rel Acquire/Release
memory_order_seq_cst Sequentially consistent

pre-increment (1)
T operator++() volatile noexcept;
T operator++() noexcept;
post-increment (2)
T operator++ (int) volatile noexcept;
T operator++ (int) noexcept;

if T is integral (1)
T operator+= (T val) volatile noexcept;
T operator+= (T val) noexcept;
T operator-= (T val) volatile noexcept;
T operator-= (T val) noexcept;
T operator&= (T val) volatile noexcept;
T operator&= (T val) noexcept;
T operator|= (T val) volatile noexcept;
T operator|= (T val) noexcept;
T operator^= (T val) volatile noexcept;
T operator^= (T val) noexcept;
if T is pointer (2)
T operator+= (ptrdiff_t val) volatile noexcept;
T operator+= (ptrdiff_t val) noexcept;
T operator-= (ptrdiff_t val) volatile noexcept;
T operator-= (ptrdiff_t val) noexcept;

以上各个 operator 都会有对应的 fetch_* 操作,详细见下表:

操作符 成员函数 支持类型
复合赋值 等价于 整型 指针类型 其他类型
+ atomic::operator+= atomic::fetch_add
- atomic::operator-= atomic::fetch_sub
& atomic::operator&= atomic::fetch_and
| atomic::operator|= atomic::fetch_or
^ atomic::operator^= atomic::fetch_xor

好了,本节先介绍这里,下一节我会介绍 C++11 中 C 风格的原子操作 API。

 

 

前面三篇文章《C++11 并发指南六(atomic 类型详解一 atomic_flag 介绍)》、《C++11 并发指南六( <atomic> 类型详解二 std::atomic )》、《C++11 并发指南六(atomic 类型详解三 std::atomic (续))》都是采用 C++ 的方式介绍原子对象,本节我会给大家介绍 C++11 原子操作中 C 风格的 API。

总地来说,C++11 标准中规定了两大类原子对象,std::atomic_flag 和 std::atomic,前者 std::atomic_flag 一种最简单的原子布尔类型,只支持两种操作,test-and-set 和 clear。而 std::atomic 是模板类,一个模板类型为 T 的原子对象中封装了一个类型为 T 的值,并且C++11 标准中除了定义基本 std::atomic 模板类型外,还提供了针对整形(integral)和指针类型的特化实现,提供了大量的 API,极大地方便了开发者使用。下面我分别介绍基于 std::atomic_flag 和 std::atomic 的 C 风格 API。

基于 std::atomic_flag 类型的 C 风格 API

bool atomic_flag_test_and_set (volatile atomic_flag* obj) noexcept;
bool atomic_flag_test_and_set (atomic_flag* obj) noexcept;
bool atomic_flag_test_and_set (volatile atomic_flag* obj, memory_order sync) noexcept;
bool atomic_flag_test_and_set (atomic_flag* obj, memory_order sync) noexcept;
Memory Order 值Memory Order 类型
memory_order_relaxedRelaxed
memory_order_consumeConsume
memory_order_acquireAcquire
memory_order_releaseRelease
memory_order_acq_relAcquire/Release
memory_order_seq_cstSequentially consistent
void atomic_flag_clear (volatile atomic_flag* obj) noexcept;
void atomic_flag_clear (atomic_flag* obj) noexcept;
void atomic_flag_clear (volatile atomic_flag* obj, memory_order sync) noexcept;
void atomic_flag_clear (atomic_flag* obj, memory_order sync) noexcept;
Memory Order 值Memory Order 类型
memory_order_relaxedRelaxed
memory_order_consumeConsume
memory_order_acquireAcquire
memory_order_releaseRelease
memory_order_acq_relAcquire/Release
memory_order_seq_cstSequentially consistent

基于 std::atomic 模板类型的 C 风格 API

template (1)
template <class T> bool atomic_is_lock_free (const volatile atomic<T>* obj) noexcept;
template <class T> bool atomic_is_lock_free (const atomic<T>* obj) noexcept;
overloads (2)
bool atomic_is_lock_free (const volatile A* obj) noexcept;
bool atomic_is_lock_free (const A* obj) noexcept;
template (1)
template <class T> void atomic_init (volatile atomic<T>* obj, T val) noexcept;
template <class T> void atomic_init (atomic<T>* obj, T val) noexcept;
overloads (2)
void atomic_init (volatile A* obj, T val) noexcept;
void atomic_init (A* obj, T val) noexcept;
template (1)
template <class T> void atomic_store (volatile atomic<T>* obj, T val) noexcept;
template <class T> void atomic_store (atomic<T>* obj, T val) noexcept;
overloads (2)
void atomic_store (volatile A* obj, T val) noexcept;
void atomic_store (A* obj, T val) noexcept;
Memory Order 值Memory Order 类型
memory_order_relaxedRelaxed
memory_order_releaseRelease
memory_order_seq_cstSequentially consistent
template (1)
template <class T> T atomic_load (const volatile atomic<T>* obj) noexcept;
template <class T> T atomic_load (const atomic<T>* obj) noexcept;
overloads (2)
T atomic_load (const volatile A* obj) noexcept;
T atomic_load (const A* obj) noexcept;
template (1)
template <class T>
T atomic_load_explicit (const volatile atomic<T>* obj, memory_order sync) noexcept;
template <class T>
T atomic_load_explicit (const atomic<T>* obj, memory_order sync) noexcept;
overloads (2)
T atomic_load_explicit (const volatile A* obj, memory_order sync) noexcept;
T atomic_load_explicit (const A* obj, memory_order sync) noexcept;
Memory Order 值Memory Order 类型
memory_order_relaxedRelaxed
memory_order_consumeConsume
memory_order_acquireAcquire
memory_order_seq_cstSequentially consistent
template (1)
template <class T> T atomic_exchange (volatile atomic<T>* obj, T val) noexcept;
template <class T> T atomic_exchange (atomic<T>* obj, T val) noexcept;
overloads (2)
T atomic_exchange (volatile A* obj, T val) noexcept;
T atomic_exchange (A* obj, T val) noexcept;
template (1)
template <class T>
T atomic_store_explicit (volatile atomic<T>* obj, T val, memory_order sync) noexcept;
template <class T>
T atomic_store_explicit (atomic<T>* obj, T val, memory_order sync) noexcept;
overloads (2)
T atomic_store_explicit (volatile A* obj, T val, memory_order sync) noexcept;
T atomic_store_explicit (A* obj, T val, memory_order sync) noexcept;
Memory Order 值Memory Order 类型
memory_order_relaxedRelaxed
memory_order_consumeConsume
memory_order_acquireAcquire
memory_order_releaseRelease
memory_order_acq_relAcquire/Release
memory_order_seq_cstSequentially consistent
template (1)
template <class T>
bool atomic_compare_exchange_weak (volatile atomic<T>* obj, T* expected, T val) noexcept;
template <class T>
bool atomic_compare_exchange_weak (atomic<T>* obj, T* expected, T val) noexcept;
overloads (2)
bool atomic_compare_exchange_weak (volatile A* obj, T* expected, T val) noexcept;
bool atomic_compare_exchange_weak (A* obj, T* expected, T val) noexcept;
  • 相等,则用 val 替换原子对象的旧值。
  • 不相等,则用原子对象的旧值替换 expected ,因此调用该函数之后,如果被该原子对象封装的值与参数 expected 所指定的值不相等,expected 中的内容就是原子对象的旧值。
template (1)
template <class T>
bool atomic_compare_exchange_weak_explicit (volatile atomic<T>* obj,
        T* expected, T val, memory_order success, memory_order failure) noexcept;
template <class T>
bool atomic_compare_exchange_weak_explicit (atomic<T>* obj,
        T* expected, T val, memory_order success, memory_order failure) noexcept;
overloads (2)
bool atomic_compare_exchange_weak_explicit (volatile A* obj,
        T* expected, T val, memory_order success, memory_order failure) noexcept;
bool atomic_compare_exchange_weak_explicit (A* obj,
        T* expected, T val, memory_order success, memory_order failure) noexcept;
  • 相等,则用 val 替换原子对象的旧值。
  • 不相等,则用原子对象的旧值替换 expected ,因此调用该函数之后,如果被该原子对象封装的值与参数 expected 所指定的值不相等,expected 中的内容就是原子对象的旧值。
Memory Order 值Memory Order 类型
memory_order_relaxedRelaxed
memory_order_consumeConsume
memory_order_acquireAcquire
memory_order_releaseRelease
memory_order_acq_relAcquire/Release
memory_order_seq_cstSequentially consistent
template (1)
template <class T>
bool atomic_compare_exchange_strong (volatile atomic<T>* obj, T* expected, T val) noexcept;
template <class T>
bool atomic_compare_exchange_strong (atomic<T>* obj, T* expected, T val) noexcept;
overloads (2)
bool atomic_compare_exchange_strong (volatile A* obj, T* expected, T val) noexcept;
bool atomic_compare_exchange_strong (A* obj, T* expected, T val) noexcept;
  • 相等,则用 val 替换原子对象的旧值。
  • 不相等,则用原子对象的旧值替换 expected ,因此调用该函数之后,如果被该原子对象封装的值与参数 expected 所指定的值不相等,expected 中的内容就是原子对象的旧值。
template (1)
template <class T>
bool atomic_compare_exchange_strong_explicit (volatile atomic<T>* obj,
        T* expected, T val, memory_order success, memory_order failure) noexcept;
template <class T>
bool atomic_compare_exchange_strong_explicit (atomic<T>* obj,
        T* expected, T val, memory_order success, memory_order failure) noexcept;
overloads (2)
bool atomic_compare_exchange_strong_explicit (volatile A* obj,
        T* expected, T val, memory_order success, memory_order failure) noexcept;
bool atomic_compare_exchange_strong_explicit (A* obj,
        T* expected, T val, memory_order success, memory_order failure) noexcept;
  • 相等,则用 val 替换原子对象的旧值。
  • 不相等,则用原子对象的旧值替换 expected ,因此调用该函数之后,如果被该原子对象封装的值与参数 expected 所指定的值不相等,expected 中的内容就是原子对象的旧值。
Memory Order 值Memory Order 类型
memory_order_relaxedRelaxed
memory_order_consumeConsume
memory_order_acquireAcquire
memory_order_releaseRelease
memory_order_acq_relAcquire/Release
memory_order_seq_cstSequentially consistent
template (integral) (1)
template <class T> T atomic_fetch_add (volatile atomic<T>* obj, T val) noexcept;
template <class T> T atomic_fetch_add (atomic<T>* obj, T val) noexcept;
template (pointer) (2)
template <class U> U* atomic_fetch_add (volatile atomic<U*>* obj, ptrdiff_t val) noexcept;
template <class U> U* atomic_fetch_add (atomic<U*>* obj, ptrdiff_t val) noexcept;
overloads (3)
T atomic_fetch_add (volatile A* obj, M val) noexcept;
T atomic_fetch_add (A* obj, M val) noexcept;
template (integral) (1)
template <class T>
T atomic_fetch_add_explicit (volatile atomic<T>* obj,
                             T val, memory_order sync) noexcept;
template <class T>
T atomic_fetch_add_explicit (atomic<T>* obj,
                             T val, memory_order sync) noexcept;
template (pointer) (2)
template <class U>
U* atomic_fetch_add_explicit (volatile atomic<U*>* obj,
                              ptrdiff_t val, memory_order sync) noexcept;
template <class U>
U* atomic_fetch_add_explicit (atomic<U*>* obj,
                              ptrdiff_t val, memory_order sync) noexcept;
overloads (3)
T atomic_fetch_add_explicit (volatile A* obj, M val, memory_order sync) noexcept;
T atomic_fetch_add_explicit (A* obj, M val, memory_order sync) noexcept;
Memory Order 值Memory Order 类型
memory_order_relaxedRelaxed
memory_order_consumeConsume
memory_order_acquireAcquire
memory_order_releaseRelease
memory_order_acq_relAcquire/Release
memory_order_seq_cstSequentially consistent
template (integral) (1)
template <class T> T atomic_fetch_sub (volatile atomic<T>* obj, T val) noexcept;
template <class T> T atomic_fetch_sub (atomic<T>* obj, T val) noexcept;
template (pointer) (2)
template <class U> U* atomic_fetch_sub (volatile atomic<U*>* obj, ptrdiff_t val) noexcept;
template <class U> U* atomic_fetch_sub (atomic<U*>* obj, ptrdiff_t val) noexcept;
overloads (3)
T atomic_fetch_sub (volatile A* obj, M val) noexcept;
T atomic_fetch_sub (A* obj, M val) noexcept;
template (integral) (1)
template <class T>
T atomic_fetch_sub_explicit (volatile atomic<T>* obj,
                             T val, memory_order sync) noexcept;
template <class T>
T atomic_fetch_sub_explicit (atomic<T>* obj,
                             T val, memory_order sync) noexcept;
template (pointer) (2)
template <class U>
U* atomic_fetch_sub_explicit (volatile atomic<U*>* obj,
                              ptrdiff_t val, memory_order sync) noexcept;
template <class U>
U* atomic_fetch_sub_explicit (atomic<U*>* obj,
                              ptrdiff_t val, memory_order sync) noexcept;
overloads (3)
T atomic_fetch_sub_explicit (volatile A* obj, M val, memory_order sync) noexcept;
T atomic_fetch_sub_explicit (A* obj, M val, memory_order sync) noexcept;
Memory Order 值Memory Order 类型
memory_order_relaxedRelaxed
memory_order_consumeConsume
memory_order_acquireAcquire
memory_order_releaseRelease
memory_order_acq_relAcquire/Release
memory_order_seq_cstSequentially consistent
emplate (integral) (1)
template <class T> T atomic_fetch_and (volatile atomic<T>* obj, T val) noexcept;
template <class T> T atomic_fetch_and (atomic<T>* obj, T val) noexcept;
overloads (2)
T atomic_fetch_and (volatile A* obj, T val) noexcept;
T atomic_fetch_and (A* obj, T val) noexcept;
template (integral) (1)
template <class T>
T atomic_fetch_and_explicit (volatile atomic<T>* obj,
                             T val, memory_order sync) noexcept;
template <class T>
T atomic_fetch_and_explicit (atomic<T>* obj,
                             T val, memory_order sync) noexcept;
overloads (2)
T atomic_fetch_and_explicit (volatile A* obj, T val, memory_order sync) noexcept;
T atomic_fetch_and_explicit (A* obj, T val, memory_order sync) noexcept;
Memory Order 值Memory Order 类型
memory_order_relaxedRelaxed
memory_order_consumeConsume
memory_order_acquireAcquire
memory_order_releaseRelease
memory_order_acq_relAcquire/Release
memory_order_seq_cstSequentially consistent
template (integral) (1)
template <class T> T atomic_fetch_or (volatile atomic<T>* obj, T val) noexcept;
template <class T> T atomic_fetch_or (atomic<T>* obj, T val) noexcept;
overloads (2)
T atomic_fetch_or (volatile A* obj, T val) noexcept;
T atomic_fetch_or (A* obj, T val) noexcept;
template (integral) (1)
template <class T>
T atomic_fetch_or_explicit (volatile atomic<T>* obj,
                             T val, memory_order sync) noexcept;
template <class T>
T atomic_fetch_or_explicit (atomic<T>* obj,
                             T val, memory_order sync) noexcept;
overloads (2)
T atomic_fetch_or_explicit (volatile A* obj, T val, memory_order sync) noexcept;
T atomic_fetch_or_explicit (A* obj, T val, memory_order sync) noexcept;
Memory Order 值Memory Order 类型
memory_order_relaxedRelaxed
memory_order_consumeConsume
memory_order_acquireAcquire
memory_order_releaseRelease
memory_order_acq_relAcquire/Release
memory_order_seq_cstSequentially consistent
template (integral) (1)
template <class T> T atomic_fetch_xor (volatile atomic<T>* obj, T val) noexcept;
template <class T> T atomic_fetch_xor (atomic<T>* obj, T val) noexcept;
overloads (2)
T atomic_fetch_xor (volatile A* obj, T val) noexcept;
T atomic_fetch_xor (A* obj, T val) noexcept;
template (integral) (1)
template <class T>
T atomic_fetch_xor_explicit (volatile atomic<T>* obj,
                             T val, memory_order sync) noexcept;
template <class T>
T atomic_fetch_xor_explicit (atomic<T>* obj,
                             T val, memory_order sync) noexcept;
overloads (2)
T atomic_fetch_xor_explicit (volatile A* obj, T val, memory_order sync) noexcept;
T atomic_fetch_xor_explicit (A* obj, T val, memory_order sync) noexcept;
Memory Order 值Memory Order 类型
memory_order_relaxedRelaxed
memory_order_consumeConsume
memory_order_acquireAcquire
memory_order_releaseRelease
memory_order_acq_relAcquire/Release
memory_order_seq_cstSequentially consistent

与原子对象初始化相关的宏

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值