vs2017下原子操作和互斥锁性能比较

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

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

原子操作:

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

using namespace std;
atomic_int num;


void run()
{
	for (int i = 0; i < 1000000; i++)
	{
		num++;
	}
}

int main()
{
	clock_t begin = clock();
	thread t1(run);
	thread t2(run);
	t1.join();
	t2.join();
	clock_t end = clock();
	cout << num << endl;
	cout << end - begin << endl;

	while (1);

	return 0;
}

运行时间:
在这里插入图片描述

互斥锁操作:

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

using namespace std;
int num;
mutex m;

void run()
{
	for (int i = 0; i < 1000000; i++)
	{
		m.lock();
		num++;
		m.unlock();
	}
}

int main()
{
	clock_t begin = clock();
	thread t1(run);
	thread t2(run);
	t1.join();
	t2.join();
	clock_t end = clock();
	cout << num << endl;
	cout << end - begin << endl;

	while (1);

	return 0;
}

运行时间:
在这里插入图片描述

互斥对象的使用,保证了同一时刻只有唯一的一个线程对这个共享进行访问,从执行的结果来看,互斥对象保证了结果的正确性,但是也有非常大的性能损失,从刚才的297ms变成了现在的782,耗时只是使用mutex互斥对象的四分之一。

原子操作的实现跟普通数据类型类似,但是它能够在保证结果正确的前提下,提供比mutex等锁机制更好的性能,如果我们要访问的共享资源可以用原子数据类型表示,那么在多线程程序中使用这种新的等价数据类型,是一个不错的选择。

在中低程度的竞争下,原子变量能提供更高的可伸缩性(锁在发生竞争时会挂起线程,从而降低了CPU的使用率和共享内存总线上的同步通信量),而在高强度的竞争下,锁能够更有效地避免竞争。

猜你喜欢

转载自blog.csdn.net/qq_23350817/article/details/90040784