C++中使用原子类型(atomic)保证多线程对数据的互斥访问

C++11中,对于多线程访问的变量,可以将其声明为原子类型,之后就不需要为原子数据类型显式地声明互斥锁或调用加锁、解锁的API,线程就能够对原子类型变量进行互斥地访问。

1、原子操作:就是多线程程序中“最小的且不可并行化的”操作。
2、声明原子类型,需要头文件 atomic
3、声明原子类型后,对于其变量的操作将为原子操作

下面的程序中,分别声明全局变量为普通( int )类型和原子类型(atomic_int),然后调用三个线程对此全局变量进行操作,并且输出最终的结果。

#include <iostream>
#include <atomic>
#include <thread>
#include <windows.h>
using namespace std;

// int sum = 0;     // 普通类型
atomic_int sum = 0; // 原子类型

void func() 
{
	for (int i = 0; i < 100; ++i)
	{
		Sleep(1);	// 每次计算前,先等待 1 毫秒,保证三个线程交错对 sum 进行操作
		sum += i;
	}
}

int main()
{
	// 声明三个线程对 sum 进行操作
	thread t1(func);
	thread t2(func);
	thread t3(func);

	// 等待所有的操作完成
	t1.join();
	t2.join();
	t3.join();

	// 观察 sum 的值,是否因为多个线程同时访问,导致非原子性操作,从而使得计算结果错误
	// 如果运行每次的值都不同,则说明非原子性操作导致数值叠加的不正确
	// 使用原子类型atomic_*,可保证对变量的访问为原子操作,每次计算的值都是正确的
	cout << "sum = " << sum << endl; // 正确结果:14850

	return EXIT_SUCCESS;
}

经过执行测试后,发现声明为原子类型(atomic_int)的变量每次执行结果都是正确的,而声明为普通类型的变量,由于非原子性操作,对于变量未进行加锁保护,整个操作过程三个线程交错进行,导致叠加结果产生差异,每次执行的结果都不一致(注:也可能会有执行正确的时候,但是是一个概率问题)。

当将func()中的for循环扩大或增加Sleep()中的时间,问题更为明显。

由此可见,使用原子类型可以很好的适应多线程环境下对于变量的读写操作,而且代码也很简洁,避免了复杂的锁机制。

上述程序只声明了atomic_int的原子类型,其他原子类型及类型支持的操作见下图:
在这里插入图片描述
在这里插入图片描述

图片来自《深入理解C++11:C++11新特性解析与应用》

至于此特性是否可以广泛应用到实际的工程代码中,而完全抛弃读写锁、互斥量等机制,目前还未经过验证,仍有待证实吧。

不过初次见到此特性的话,真的会产生让人眼前一亮的感觉,尤其是习惯使用读写锁来对共享变量进行保护的操作,看到原子类型是否有种柳暗花明又一村的感觉?

谢谢阅读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值