c++11 atomic 之 atomic 使用

c++11 atomic 之 atomic 使用

1、atomic支持的数据类型

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

contained typeatomic c-stype
boolatomic_bool
charatomic_char
signed charatomic_schar
unsigned charatomic_uchar
shortatomic_short
unsigned shortatomic_ushort
intatomic_int
unsigned intatomic_uint
longatomic_long
unsigned longatomic_ulong
long longatomic_llong
unsigned long longatomic_ullong
wchar_tatomic_wchar_t
char16_tatomic_char16_t
char32_tatomic_char32_t
intmax_tatomic_intmax_t
uintmax_tatomic_uintmax_t
int_leastN_tatomic_int_leastN_t
uint_leastN_tatomic_uint_leastN_t
int_fastN_tatomic_int_fastN_t
uint_fastN_tatomic_uint_fastN_t
intptr_tatomic_intptr_t
uintptr_tatomic_uintptr_t
size_tatomic_size_t
ptrdiff_tatomic_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).


Parametersdescribe
objPointer 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).
valValue 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类型 而提供的操作
操作trivint typeptr type效果
atomic a = valyesyesyes以val为a的初值(这个不是atomic 的操作)
atomic a; atomic_init(&a,val)yesyesyes同上 (若无后面的atomic_init(),则a的初始化不完整)
a.is_lock_free()yesyesyes如果内部不使用lock则返回true 用来检测atomic类型内部是否由于使用lock才成为atomic。如果不是,则硬件本身就拥有对atomic操作的固有支持
a.store(val)yesyesyes赋值 val (返回void)
a.load()yesyesyes返回数值a的copy
a.exchange(val)yesyesyes赋值val并返回旧值a的拷贝
a.compare_exchange_strong(exp,des)yesyesyescas操作
a.compare_exchange_weak(exp,des)yesyesyesweak cas操作
a = valyesyesyes赋值并返回val的拷贝(copy)
a.operator atomic()yesyesyes返回数值a的拷贝
a.fetch_add(val)noyesyes不可切割值 a += val 并返回新值得拷贝
a.fetch_sub(val)noyesyes不可切割值 a -= val 并返回新值得拷贝
a += valnoyesyes等同于 t.fetch_add(val)
a -= valnoyesyes等同于 t.fetch_sub(val)
++a a++noyesyes等同于 t.fetch_add(1) 并返回 a 或者a+1的拷贝
–a a–noyesyes等同于 t.fetch_sub(1) 并返回 a 或者a+1的拷贝
a.fetch_and(val)noyesno不可切割值 a &= val 并返回新值得拷贝
a.fetch_or(val)noyesno不可切割值 a
a.fetch_and(val)noyesno不可切割值 a ^= val 并返回新值得拷贝
a &= valnoyesno等同于 t.fetch_and(val)
a= valnoyesno
a= valnoyesno

关于以上几点说明:

  • 所有函数,除了构造函数,都被重载为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++标准库第二版》

  • 19
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言中的`<stdatomic.h>`库提供了原子操作接口,用于实现线程安全的原子操作。原子操作是不可被中断的,即在执行原子操作期间不会有其他线程干扰。 在C11标准中,`<stdatomic.h>`库引入了一组原子类型和原子操作函数。这些原子类型和函数可以用于实现共享变量的原子访问、更新和同步。 下面是一些常用的原子类型和相关函数: 1. `atomic_flag`类型:用于简单的原子标志操作,只有两个操作:`atomic_flag_test_and_set()`和`atomic_flag_clear()`。 2. 原子整型类型(如`atomic_int`、`atomic_uint`等):支持常见的整型操作,如赋值、加法、减法、比较交换等。 3. 原子指针类型(如`atomic_intptr_t`、`atomic_ptrdiff_t`等):支持指针类型的原子操作,如原子加载、存储和比较交换等。 4. `atomic_thread_fence()`函数:用于实现内存屏障,确保指令重排序不会破坏多线程程序的正确性。 5. `atomic_load()`和`atomic_store()`函数:用于原子加载和存储操作。 6. `atomic_exchange()`函数:用于原子交换操作,可以原子地交换一个值并返回旧值。 7. `atomic_compare_exchange_strong()`和`atomic_compare_exchange_weak()`函数:用于原子比较并交换操作,可以原子地比较并交换一个值。 通过使用这些原子类型和函数,我们可以实现线程安全的并发操作。注意,原子操作并不意味着完全的线程同步,额外的同步机制(如互斥锁)可能仍然是必需的来确保正确的并发访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值