十、原子操作
本节主要记录原子操作std::atomic
类模板的使用。
1、原子操作概念引出
有两个线程,对一个全局变量进行操作,一个线程读变量值,另一个线程向这个变量中写值。
1 |
|
上述代码创建了两个线程,两个线程都是对全局变量global_val进行++运算。常理上讲,当两个线程执行完毕并返回后,global_val = 20000000。但是运行上述代码,我们发现并不是这样,global_val<<20000000 !这是因为我们进行++操作时,尽管看起来只有一行代码,但是实际上编译之后会产生多行汇编代码,在进行++运算的过程中,系统切换到了另外一个线程,打断了原来线程的++操作。
知道了问题所在,我们便有对应的解决方法,使用我们之前学到的互斥量,对共享数据进行保护,使得其他线程不会打断本线程的操作,上述代码会进行20000000次的加锁、解锁操作,尽管比较费时,但是结果是正确的,程序耗时大约5秒。
原子操作,一般都是指”不可分割的操作“,也就是说这种操作状态要么是完成的,要么是未完成的,不可能出现半完成状态。原子操作适用于上述的情况,我们可以把原子操作理解成一种:不需要用到互斥量加锁技术的多线程并发编程方式。或者也可以理解成:原子操作是在多线程中不会被打断的程序执行片段。
互斥量的加锁一般是针对一个代码段(几行代码),而原子操作针对的一般都是一个变量,原子操作效率上比互斥量更胜一筹。
C++11中的std::atomic
来代表原子操作,它是一个类模板,用来封装某个类型的值。
2、std::atomic的基本使用
1 |
|
std::atomic
对int进行包装之后,我们可以向原来使用int一样使用包装之后的变量。使用原子操作之后,同样的操作只需要1.5秒左右。
一般std::atomic
原子操作,针对++、–、+=、&=、|=、*=运算符是支持的,其他的可能不支持。