1、 原子操作:std::atomic
【1】原子操作理解为:不需要用到互斥量加锁(无锁)技术的多线程并发编程方式,并且原子操作在多线程中不会被打断执行;
【2】原子操作比互斥量在效率上更高;
【3】互斥量的加锁一般是针对一个代码段(几行代码), 原子操作针对的都是一个变量,而不是针对一个代码段;
【4】原子操作:该变量要么完成,要么没完成,不存在中间状态
std::atomic代表原子操作。std::atomic是一个类模板,用于封装某个类型的值;
2.原子操作步骤(分三步:Read ---> Modified ----> Write)
atomic是原子的意思,意味"不可分割"的整体。在Linux kernel中有一类atomic操作API。这些操作对用户而言是原子执行的,在一个CPU上执行过程中,不会被其他CPU打断。最常见的操作是原子读改写,简称RMW。
【1】单个CPU的情况
一个变量自增操作,CPU微观指令级别分成3步操作。
1) 先read变量的值到CPU内存寄存器; //读:Read
2) 对寄存器的值递增;//改:Modified
3) 将寄存器的值写回变量。//写: Write
3.多线程访问一个变量例子
【1】有两个线程,线程thread1对变量aa读操作,线程thread2对变量中写值。
int aa = 5;
【2】在线程thread1里,对aa读操作,放入tmp变量中,以后使用
int tmp = aa ;//aa代表的是多个线程之间要共享的变量
【3】在线程thread2里,对aa写操作
aa = 100;
结果:原本是想读出来aa = 5的值,结果可能读出来是已经修改的值100,不是自己想要的脏数据,所以对变量读写要保持其原子性----->即:执行中不可被打断。
原子操作:
可以把原子操作理解为:不需要用到互斥量加锁(无锁)技术的多线程编程方式,多线程中不会被打断的程序执行片段。
4.原子操作测试demo
#include <thread>
#include <atomic>
#include <iostream>
using namespace std;
//1.have atomic
//atomic<int> g_count;
//2.no atomic
int g_count = 0;
void work(){
for (int i = 0;i < 100000;i++){
g_count++;
}
return;
}
int main(){
std::thread t1(work);
std::thread t2(work);
t1.join();
t2.join();
//如果没有使用atomic原子定义,打印的值是随机,是乱的
cout << "g_count = " << g_count << endl;
}
总结:
1.先理解下CPU和内存连接方式
在SMP系统中,多个CPU通过共享的总线和内存相连接,如果它们同时申请访问内存,那么总线就会从硬件上进行仲裁,以确定接下来哪一个CPU可以使用总线,然后将总线授权给它,并且允许该CPU完成一次原子的load操作或者store操作。在完成每一次操作之后,就会重复这个周期:对总线进行仲裁,并授权给另一个CPU。每次只能有一个CPU使用总线。
2.理解原子操作
原子操作常用的做法是给总线上锁(bus lock),以获得在一定的时间窗口内对总线独占的授权,就好像是一个CPU在告诉总线说“在我完成之前,别让其他CPU来读写内存的数据”。