c++11 atomic 之 atomic 使用

c++11 atomic 之 atomic 使用

1、atomic支持的数据类型

atomic 原子操作支持bool、int、char等数据数据类型,但是不支持浮点数类型 ,下表为基本数据类型、c-style支持的类型、对应的atomic类型

contained type atomic c-stype
bool atomic_bool
char atomic_char
signed char atomic_schar
unsigned char atomic_uchar
short atomic_short
unsigned short atomic_ushort
int atomic_int
unsigned int atomic_uint
long atomic_long
unsigned long atomic_ulong
long long atomic_llong
unsigned long long atomic_ullong
wchar_t atomic_wchar_t
char16_t atomic_char16_t
char32_t atomic_char32_t
intmax_t atomic_intmax_t
uintmax_t atomic_uintmax_t
int_leastN_t atomic_int_leastN_t
uint_leastN_t atomic_uint_leastN_t
int_fastN_t atomic_int_fastN_t
uint_fastN_t atomic_uint_fastN_t
intptr_t atomic_intptr_t
uintptr_t atomic_uintptr_t
size_t atomic_size_t
ptrdiff_t atomic_ptrdiff_t

比较详细的解释详见

c++ atomic

2、atomic 构造以及初始化

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

default (1)atomic() noexcept = default;
initialization (2)constexpr atomic (T val) noexcept;
copy [deleted] (3)	:atomic (const atomic&) = delete;
  • 默认构造函数:由默认构造函数创建的 std::atomic 对象处于未初始化(uninitialized)状态,对处于未初始化(uninitialized)状态 std::atomic对象可以由 atomic_init 函数进行初始化。
  • 初始化构造函数:由类型 T初始化一个 std::atomic对象。
  • 拷贝构造函数被禁用:定义时直接进行初始化例如:

注意我们使用时应该将 atomic object 进行初始化,因为默认的构造函数并不完全初始化他(并不是因为其初始值不明确,而是其lock未被初始化)。对于一个static-duration atomic 对象,我们应该使用一个常量作为初始值,如果我们只是使用默认的构造函数,接下来唯一允许的操作是如下调用:

std::atomic<bool> test;
std::atomic_init(&test,false);

利用初始化构造函数

std::atomic <bool>   atomic_bool_test1(false);
std::atomic <int>   atomic_int_test1(0);

对于 atomic_flag直接用ATOMIC_FLAG_INIT进行初始化

std::atomic_flag mutex = ATOMIC_FLAG_INIT; 

对于atomic_init c++ 官网参考文档如下:

std::atomic_init
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;
Initialize atomic object
Initializes obj with a contained value of val.

Calling this function on an atomic object that has already been initialized (either on construction or by calling this function earlier) causes undefined behavior (see atomic_store to modify the value of already-initialized atomics).


Parameters describe
obj Pointer to an atomic object.Type A represents other overloaded atomic types (in case the library does not implement the C-style atomic types as instantiations of atomic).
val Value to initialize the contained object with.T is the type of the value contained by the atomic object (atomic’s template parameter).

初始化原子对象。val 指定原子对象的初始值。如果对一个已初始化的原子对象再次调用 atomic_init(),则会导致未定义行为(undefined behavior),如果你想修改原子对象的值,应该使用 std::atomic_store();

使用示例

#include <atomic>
#include <iostream>

int main(void)
{
    std::atomic_flag  atomic_flag_test = ATOMIC_FLAG_INIT;
    std::cout << "init atomic_flag_test "<<atomic_flag_test.test_and_set()<<std::endl;

    std::atomic_bool  atomic_bool_test1;
    std::atomic_init(&atomic_bool_test1,false);
    std::cout << "init atomic_bool_test1 "<<atomic_bool_test1<<std::endl;

    std::atomic<bool> atomic_bool_test2;
    std::atomic_init(&atomic_bool_test2,true);
    std::cout << "init atomic_bool_test2 "<<atomic_bool_test2<<std::endl;

    std::atomic<int> atomic_int_test1(100);
    std::cout << "init atomic_int_test1 "<<atomic_int_test1<<std::endl;

    std::atomic<int> atomic_int_test2;
    std::atomic_init(&atomic_int_test2,200);
    std::cout << "init atomic_int_test2 "<<atomic_int_test2<<std::endl;

}
root@wan:/wan/temp/c++11实现原子操作# g++ -o atomic_init atomic_init.cpp
root@wan:/wan/temp/c++11实现原子操作# ./atomic_init
init atomic_flag_test 0
init atomic_bool_test1 0
init atomic_bool_test2 1
init atomic_int_test1 100
init atomic_int_test2 200

3、atomic 相关接口

atomic 相关的接口以下面列表的形式展现出来:

  • 纵列 triv :针对std::atomic以及“其他普通类型之atomic”提供的操作
  • 纵列 int type :针对std::atomic<> 且使用整型类型而提供的操作;
  • 纵列 ptr type :针对std::atomic<> 且使用pointer类型 而提供的操作
操作 triv int type ptr type 效果
atomic a = val yes yes yes 以val为a的初值(这个不是atomic 的操作)
atomic a; atomic_init(&a,val) yes yes yes 同上 (若无后面的atomic_init(),则a的初始化不完整)
a.is_lock_free() yes yes yes 如果内部不使用lock则返回true 用来检测atomic类型内部是否由于使用lock才成为atomic。如果不是,则硬件本身就拥有对atomic操作的固有支持
a.store(val) yes yes yes 赋值 val (返回void)
a.load() yes yes yes 返回数值a的copy
a.exchange(val) yes yes yes 赋值val并返回旧值a的拷贝
a.compare_exchange_strong(exp,des) yes yes yes cas操作
a.compare_exchange_weak(exp,des) yes yes yes weak cas操作
a = val yes yes yes 赋值并返回val的拷贝(copy)
a.operator atomic() yes yes yes 返回数值a的拷贝
a.fetch_add(val) no yes yes 不可切割值 a += val 并返回新值得拷贝
a.fetch_sub(val) no yes yes 不可切割值 a -= val 并返回新值得拷贝
a += val no yes yes 等同于 t.fetch_add(val)
a -= val no yes yes 等同于 t.fetch_sub(val)
++a a++ no yes yes 等同于 t.fetch_add(1) 并返回 a 或者a+1的拷贝
–a a– no yes yes 等同于 t.fetch_sub(1) 并返回 a 或者a+1的拷贝
a.fetch_and(val) no yes no 不可切割值 a &= val 并返回新值得拷贝
a.fetch_or(val) no yes no 不可切割值 a
a.fetch_and(val) no yes no 不可切割值 a ^= val 并返回新值得拷贝
a &= val no yes no 等同于 t.fetch_and(val)
a = val no yes no
a = val no yes no

关于以上几点说明:

  • 所有函数,除了构造函数,都被重载为volatile和non-volatile两个版本

4、有关CAS接口使用

compare_exchange_strong() 和 compare_exchange_weak()
这两个接口都是CAS操作(compare and swap)。cpu常常提供这个atomic操作用以比较“某内存内容”和“某给定值”,并且唯有在它们相同时才将该内存区内容更新为另一给定的新值。这可以保证新值乃是根据最新信息计算出来的。
伪代码如下:

bool compare_exchange_strong(T & expected ,T desired)
{
 if(this->load() == expected )
 {
 	this->strore(desired)
 	return true;
 }
 else
 {
	expected = this->load();
	return false;
}
}

weak 和strong 的区别:
weak 形式有可能出现假失败(spuriously fail),即:期望值出现它仍然返回false。但是weak形式有时比strong形式更高效。

5、使用例子

#include <atomic>
#include <future>
#include <thread>
#include <chrono>
#include <iostream>

long data = 0;
std:: atomic<bool> readFlag(false);

void provider (void)
{
    std::cout<<"return"<<std::endl;
    std::cin.get();
    data = 9527;
    readFlag.store(true);
}

void consumer(void)
{
    while(!readFlag.load())
    {
        std::cout.put('.').flush();
        std:: this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
    std::cout << "data "<<data<<std::endl;
}

int main(void)
{
    auto p = std::async(std::launch::async,provider);
    auto c = std::async(std::launch::async,consumer);
}

编译运行:

 g++ -o atomic_use atomic_use.cpp  -lpthread
./atomic_use


.return
.
data 9527

6 参考

http://www.cplusplus.com/reference/atomic/
https://www.cnblogs.com/haippy/p/3306625.html
《c++标准库第二版》

发布了67 篇原创文章 · 获赞 15 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/wanxuexiang/article/details/104280021