C++11之atomic原子操作

  • atomic介绍

atomic对int、char、bool等数据结构进行了原子性封装,在多线程环境中,对std::atomic对象的访问不会造成竞争-冒险。利用std::atomic可实现数据结构的无锁设计。

所谓的原子操作,取的就是“原子是最小的、不可分割的最小个体”的意义,它表示在多个线程访问同一个全局资源的时候,能够确保所有其他的线程都不在同一时间内访问相同的资源。也就是他确保了在同一时刻只有唯一的线程对这个资源进行访问。这有点类似互斥对象对共享资源的访问的保护,但是原子操作更加接近底层,因而效率更高。

在以往的C++标准中并没有对原子操作进行规定,我们往往是使用汇编语言,或者是借助第三方的线程库,例如intel的pthread来实现。在新标准C++11,引入了原子操作的概念,并通过这个新的头文件提供了多种原子操作数据类型,例如,atomic_bool,atomic_int等等,如果我们在多个线程中对这些类型的共享资源进行操作,编译器将保证这些操作都是原子性的,也就是说,确保任意时刻只有一个线程对这个资源进行访问,编译器将保证,多个线程访问这个共享资源的正确性。从而避免了锁的使用,提高了效率。

  • atomic高效体现

加锁不使用atomic:

#include <iostream>
#include <ctime>
#include <mutex>
#include <vector>
#include <thread>

std::mutex mtx;
size_t count = 0;

void threadFun()
{
	for (int i = 0; i < 10000; i++)
	{
		// 防止多个线程同时访问同一资源
		std::unique_lock<std::mutex> lock(mtx);
		count++;
	}
}

int main(void)
{
	clock_t start_time = clock();

	// 启动多个线程
	std::vector<std::thread> threads;
	for (int i = 0; i < 10; i++)
		threads.push_back(std::thread(threadFun));
	for (auto&thad : threads)
		thad.join();

	// 检测count是否正确 10000*10 = 100000
	std::cout << "count number:" << count << std::endl;

	clock_t end_time = clock();
	std::cout << "耗时:" << end_time - start_time << "ms" << std::endl;

	return 0;
}

运行结果

使用atomic:

#include <iostream>
#include <ctime>
#include <vector>
#include <thread>
#include <atomic>


std::atomic<size_t> count(0);

void threadFun()
{
	for (int i = 0; i < 10000; i++)
		count++;
}

int main(void)
{
	clock_t start_time = clock();

	// 启动多个线程
	std::vector<std::thread> threads;
	for (int i = 0; i < 10; i++)
		threads.push_back(std::thread(threadFun));
	for (auto&thad : threads)
		thad.join();

	// 检测count是否正确 10000*10 = 100000
	std::cout << "count number:" << count << std::endl;

	clock_t end_time = clock();
	std::cout << "耗时:" << end_time - start_time << "ms" << std::endl;

	return 0;
}
运行结果

总结

从上面的截图可以发现,第一张图用时2439ms,第二张图用时13ms,使用原子操作能大大的提高程序的运行效率。

附:很多读者不理解为什么在后面另起一个for循环进行join,对于这个问题,我希望读者自己先了解下join的用法。

实际上线程在上一个for循环创建的时候就已经开始运行了,join只是为了阻塞主线程,用于等待所有子线程完成,不然子线程还未执行完,主线程就已经结束了(同时也方便我这边计时)。

同时为什么不能创建线程后立刻join,也是上面说的join会阻塞主线程,主线程被阻塞了,for循环就得等子线程执行完后才会继续创建新的线程了,这种压根不涉及并发执行,不涉及资源竞争的问题,是串行的。

  • 参考文档
博客地址:https://blog.csdn.net/yockie/article/details/8838686
  • 22
    点赞
  • 112
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值