C++11多线程(五)原子操作简单使用

C++11多线程(五)原子操作简单使用

以下都是原子的简单使用,后续深入了解原子操作后会再记录。

概念

什么是原子?

在计算机中我们可以将其理解为“原子是无法分割的最小个体”。

什么是原子操作?

通过操作原子来实现线程对资源的安全访问,听起来和锁是差不多的,但原子操作更接近于底层,所有效率会更好。互斥锁是一种对象,使你可以执行一系列互斥操作。而原子操作是互斥的单个操作,这意味着没有其他线程可以打断它。

原子操作在运行过程中是不会被打断的,这点需要我们记住,原子操作只有完成完成和未完成状态。正是这一点,我们也可以使用原子操作来保证线程的安全性。

C++11中虽然引入了lock_guard和unique_lock等等这些锁,但在实际过程中我们追求更高效的无锁操作时,我们就可以使用原子操作来实现无锁操作。

std::atomic

在使用之前我们需要注意引入头文件#include<atomic>

#include<atomic> //引入头文件

std::atomic<int> m_atomic ; //创建原子类

从上面我们可以很清楚的看出,这是一个类模板。

atomic通过将基础数据类型封装然后供给我们使用。就比如上文的atomic就是一个封装了int类型数据的原子。使用的时候你就把他理解为一个int类型的变量来进行相应的运算符操作,比如++,–,+=,-=等运算符(具体会在之后成员方法进行介绍)。

那原子操作到底有更快呢,下面通过实际代码来看一下。

#include<iostream>
#include<thread>
#include<mutex>
#include<atomic> //引入头文件
using namespace std;

atomic<int> x(0); //声明一个int类型的原子变量x,初始值为0 
mutex mtx;
void f() {		//这段代码是用来测试线程同步的,线程同步的概念可以理解为保证数据安全性
    			//也可以尝试一下不用原子而用in来运行,有关知识之后的线程概念部分会进行讲解
	for (int i = 0; i < 100000000; i++) {//每一个线程对进行100000000次循环++
		x++;		//对原子进行++操作
	};
}

int main() {
	clock_t start = clock();   //获取运行启动时间
	thread t1(f);
	thread t2(f);

	t1.join();
	t2.join();

	clock_t	end = clock();//获取运行结束时间
	cout << x << endl;
	cout << "Run_Time:" << end - start << endl;
}

本次测试结果

在这里插入图片描述

再来看看使用锁

#include<iostream>
#include<thread>
#include<mutex>
#include<atomic>
using namespace std;
mutex mtx;
int x;
void f() {
	//mtx.lock(); 
	for (int i = 0; i < 100000000; i++) {
        //注意是在循环里进行锁住而不是在函数入口,这样才能测试锁和原子的效率对比
        //也可以用类似方法测试一下unique_lock和lock_guard,希望你还没有忘记
		mtx.lock(); 
		x++;
		mtx.unlock();
	}
	//mtx.unlock();
}

int main() {
	clock_t start = clock();   //获取运行启动时间
	thread t1(f);
	thread t2(f);

	t1.join();
	t2.join();

	clock_t	end = clock();//获取运行结束时间
	cout << x << endl;
	cout << "Run_Time:" << end - start << endl;

}

在这里插入图片描述

可以明显的看出效率差距。

atomic的方法

bool is_lock_free();
提供一个接口函数给使用者查询调用原子的实现方式
return true : 直接利用原子指令
return false : 利用编译器和库函数实现

atomic重载了这几个运算符

&=,++,+=,–,-=,=,^=,|=

这几个运算符的用法和基础数据类型是一样的,在这里不多做解释。

值得一提的是,atomic也禁用了拷贝构造函数。

atomic常用的方法也就load()和store()

atomic::load() 读原子操作

atomic::store() 写原子操作

这里稍微提一下 运算符赋值和 load()/store()的区别
load是取值,“=”是赋值,不是一回事,取值的方式有两种,一种是通过load取值,另一种直接用创建的示例取值(这种方式实际调用的是仿函数,即重载了“()”运算符,再通过仿函数调用 load() 实现取值) 2、赋值方式 store 和“=”运算符号,差别是,store采用memcpy进行值拷贝,而重载的“=”是通过逐字节赋值而且还是值交换的方式进行,效率比store慢;另外store可以直接使用 atomic对象进行赋值,并不是有接受atomic对象的store函数,而是传入的对象会先调用仿函数获取实际值作为store的返回值,而“=”运算符自带的删除,新定义的重载“=”的函数只能接受atomic管理的示例类型的值,例如 atomic_bool 利用“=”符号只能用类型 的值而不能用atomic_bool对象赋值

此外,原子操作还有运算函数fetch_add(),fetch_sub(),。
因为本人平时使用原子的计算也只是用运算符,资料也没找到太多,不深入解析。想更深入的了解原子操作可阅读源码或者自行查阅相关资料。

快速创建原子变量

C++11还提供了我们许多宏用来快速创建原子变量。

typedef atomic<bool> atomic_bool;

typedef atomic<char> atomic_char;
typedef atomic<signed char> atomic_schar;
typedef atomic<unsigned char> atomic_uchar;
typedef atomic<short> atomic_short;
typedef atomic<unsigned short> atomic_ushort;
typedef atomic<int> atomic_int;
typedef atomic<unsigned int> atomic_uint;
typedef atomic<long> atomic_long;
typedef atomic<unsigned long> atomic_ulong;
typedef atomic<long long> atomic_llong;
typedef atomic<unsigned long long> atomic_ullong;

typedef atomic<char16_t> atomic_char16_t;
typedef atomic<char32_t> atomic_char32_t;

typedef atomic<wchar_t> atomic_wchar_t;

typedef atomic<int8_t> atomic_int8_t;
typedef atomic<uint8_t> atomic_uint8_t;
typedef atomic<int16_t> atomic_int16_t;
typedef atomic<uint16_t> atomic_uint16_t;
typedef atomic<int32_t> atomic_int32_t;
typedef atomic<uint32_t> atomic_uint32_t;
typedef atomic<int64_t> atomic_int64_t;
typedef atomic<uint64_t> atomic_uint64_t;

typedef atomic<int_least8_t> atomic_int_least8_t;
typedef atomic<uint_least8_t> atomic_uint_least8_t;
typedef atomic<int_least16_t> atomic_int_least16_t;
typedef atomic<uint_least16_t> atomic_uint_least16_t;
typedef atomic<int_least32_t> atomic_int_least32_t;
typedef atomic<uint_least32_t> atomic_uint_least32_t;
typedef atomic<int_least64_t> atomic_int_least64_t;
typedef atomic<uint_least64_t> atomic_uint_least64_t;

typedef atomic<int_fast8_t> atomic_int_fast8_t;
typedef atomic<uint_fast8_t> atomic_uint_fast8_t;
typedef atomic<int_fast16_t> atomic_int_fast16_t;
typedef atomic<uint_fast16_t> atomic_uint_fast16_t;
typedef atomic<int_fast32_t> atomic_int_fast32_t;
typedef atomic<uint_fast32_t> atomic_uint_fast32_t;
typedef atomic<int_fast64_t> atomic_int_fast64_t;
typedef atomic<uint_fast64_t> atomic_uint_fast64_t;

typedef atomic<intptr_t> atomic_intptr_t;
typedef atomic<uintptr_t> atomic_uintptr_t;
typedef atomic<size_t> atomic_size_t;
typedef atomic<ptrdiff_t> atomic_ptrdiff_t;
typedef atomic<intmax_t> atomic_intmax_t;
typedef atomic<uintmax_t> atomic_uintmax_t;

上述都在源码中被定义过。

以上都是简单使用,后续深入了解原子操作后会再记录。

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值