9 —— 原子操作std::atomic

本文探讨了在多线程环境中使用原子操作确保数据一致性的重要性。通过对比互斥量和原子变量,阐述了原子操作如何在提高并发性能的同时,避免线程间的竞争条件。文章还讨论了原子操作的限制及其在C++中的实现。

一 原子操作概念引出范例

#include <iostream>
#include <thread>

using namespace std;

int g_count = 0; // 定义一个全局量,供两个线程同时访问

void mythread()	//	线程入口函数
{
	for (int i = 0; i < 10000000; i++)
	{
		g_count++;
	}
}

int main()
{
	std::thread mytask1(mythread);
	std::thread mytask2(mythread);
	mytask1.join();
	mytask2.join();

	cout << "两个线程执行完毕,最终g_count的值是:" << g_count << endl;

	getchar();
	return 0;
}
输出结果:
	12171204     //	运行第一次结果
	12125050	//	运行第一次结果
	14455315	//	运行第一次结果

  我们原本想要输出结果为2000 0000,但是因为两个线程竞争,导致输出结果不对。
  修改如下:我们可以用互斥量来保护共享数据。

std::mutex g_mutex;

void mythread()	//	线程入口函数
{
	for (int i = 0; i < 10000000; i++)
	{
		g_mutex.lock();
		g_count++;
		g_mutex.unlock();
	}
}

  我们可以用互斥量来保护共享数据,但是由于锁的粒度,频繁的加锁解锁。输出结果的时间耗费了5-6秒的时间。那有什么办法可以提高老运行效率吗?这时就可以用上原子操作了。

#include <iostream>
#include <thread>
#include <atomic>

using namespace std;

atomic<int> g_count = 0; // 定义一个全局量,供两个线程同时访问

void mythread()	//	线程入口函数
{
	for (int i = 0; i < 10000000; i++)
	{
		g_count++;
	}
}



int main()
{
	std::thread mytask1(mythread);
	std::thread mytask2(mythread);
	mytask1.join();
	mytask2.join();

	cout << "两个线程执行完毕,最终g_count的值是:" << g_count << endl;

	getchar();
	return 0;
}

耗时省了一半,用了2-3秒。

什么是原子操作?
原子操作是指“不可分割的操作”,可以看成是一种多线程无锁编程技术。atomic是一个类模板,参数是变量的类型。通过将变量声明成原子变量,则可以保证,在多线程中,每当访问原子变量时,它的值是最新的值。它同互斥量一样,都保护了数据。但是互斥量保护的是一个代码段,可以保护更多的操作。而原子变量是保护一个变量被多个线程同时访问时,这个变量是最新的值。而不会因为线程间不同步导致结果出错。

二 原子操作注意事项

   一般原子操作对{ ++, --, +=, &=, ^=, |= … }这些运算符是支持的,其它的可能不支持。

void mythread()	//	线程入口函数
{
	for (int i = 0; i < 10000000; i++)
	{
		g_count++;	// 结果正确
		//g_count += 1; // 结果正确
		//g_count = g_count + 1; // 结果不对
	}
}

   std::atomic不支持拷贝赋值运算

std::atomic<int> atm2 = atm;	//	错误,atomic不支持赋值赋值运算, 但是atm2 = 3 可以。

std::atomic<int> atm2(atm.load());	//	正确,以原子方式读atm的值

atm.store(2);	//	正确,以原子方式写atm的值

cout << atm << endl;	
//	读atm的值是原子操作,但这整句不是原子操作,它要将atm值写入到输出流中,不能保证缓存中都是最新的atm的值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值