C++11:原子操作

在多线程开发中,为了确保数据安全性,经常需要对数据进行加锁、解锁处理。C++11中引入了原子的概念,简而言之就是访问它时它自动加锁解锁,从而使软件开发更为简便。

原子可谓一个既简单又复杂的概念。简单到访问它时就跟单线程访问一块内存一样简单,复杂的地方在于它的实现涉及到各种内存模型,在优化中经常会遇到。

下面给出一个简单的原子示例:

#include <iostream>
#include <thread>
#include <atomic>
using namespace std;

atomic_int val = { 0 };//这个类型也可以写作 atomic<int> 用于表示整型数据的原子

void icrement () {
	for (int i = 0; i < 100000000; i++) {
		val++;
	}
}

int main (int argc, char* argv []) {
	//创建两个线程
	thread t1 (icrement);
	thread t2 (icrement);
	//等待两个线程执行完
	t1.join ();
	t2.join ();
	cout << val << endl;
	return 0;
}
经过十几秒左右的等待后,代码执行完毕,结果不出所料,200000000。简单的原子操作差不多就是这样,atomic模板可以包括任何类型,另外原子的操作也与它本身的操作方式基本相同,因为原子模板重载了所有的运算符。
简单的说完了,说说复杂的原子概念。

假如一个原子,它长这样

atomic_int val = { 0 };
嗯,跟上面的相同。它实际上可以提供三种类型的操作:读、写、RMW(同时包括读写),通过三种类型的函数实现。
首先是读,比如 int i=val; 这样的代码,实际上是通过load函数实现。

int i = val.load (memory_order_seq_cst);
后面的参数代表内存顺序。这个的含义是顺序执行当前的原子操作。什么含义?含义就是,如果一个函数中对这个原子进行了多项操作,那么首先执行之前的原子操作,然后执行本条操作,最后执行之后的原子操作。说白了就是单线程的执行顺序。原子的操作过程并不是必须固定的,一个函数中如果有两条原子操作,那么首先执行后面操作,然后执行前面操作是完全可能的。这个在优化中经常会遇到。
然后是写操作,比如 val = i; 这样的操作

val.store (i, memory_order_seq_cst);
嗯,这儿也顺序执行,以免颠覆各位三观。

然后就是同时读写这样的操作了。 比如原子+=一个数之后同时可访问,通过compare_exchange这类函数实现。
然后,接下来说说内存访问模型了。一共有六种

1、memory_order_seq_cst    顺序执行,可用于读、写、RMW操作

2、memory_order_relaxed    乱序执行,可用于读、写、RMW操作

3、memory_order_acq_rel    首先执行之前的写操作,然后执行本条操作,然后执行之后的读操作,可用于RMW操作

4、memory_order_release    首先执行之前的写操作,然后执行本条操作,可用于写、RMW操作

5、memory_order_acquire    首先执行本条操作,然后执行后面的读操作,可用于读、RMW操作

6、memory_order_consume    首先执行本条操作,然后执行后面的读写操作,可用于读、RMW操作

基本的概念就是上面这些了,接下来动手实践吧

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值