线程安全
线程安全函数:当一个函数被多个并发线程反复调用的时候,它的结果始终是正确的
一般线程不安全的情况,是由于同一个进程的不同线程共享进程内存空间中的全局/静态存储区和堆,如果一个函数中包含全局变量和静态变量,那么可能会线程不安全,导致程序错误。但是如果对全局变量和静态变量的操作只有读,没有修改的话,也可以将这个函数看做是线程安全的。
C++多线程(C++11)
多线程demo
C++11的标准库,提供了多线程库,需要 #include <thread>
头文件(主要提供对线程管理的类std::thread
)
#include <iostream>
#include <thread>
using namespace std;
void output(int i){
cout << i << endl;
}
int main(){
for(uint8_t i = 0; i < 8; i++) {
thread th(output, i);
th.detach(); //detach表示该线程可以在后台运行,无需等待当前线程完成,会继续执行后面的操作
}
getchar();
return 0;
}
输出结果:
可以看到程序没有按照从1到8的顺序输出,而且不是每个数字后面都有换行。
分析:
创建了8个进程,每个进程都会调用output方法,output的过程分两步:①打印出i的值、②打印换行。
涉及到多线程最核心的问题:资源竞争。
8核CPU创建了8个线程,但是控制台只有1个,并且在同一时刻只能有一个线程占有这个唯一的控制台。
所以会出现情况:在一个线程占用控制台打印数字之后,没来得及打印换行,控制台就被另一个进程占用的情况。
C++11中的两种等待线程结束的方式:
detach方式,启动的线程自主在后台运行,当前的代码继续往下执行,不用等待进程结束。创建的新进程同时并发执行。
join方式,会阻塞当前的代码,需要等待当前启动的线程执行完成,才会继续进行下一步。
使用join方式修改之前的demo
#include <iostream>
#include <thread>
#include <sstream>
using namespace std;
void output(int i){
cout << i << endl;
}
int main(){
stringstream ss;
for(int i = 0; i < 8; i++) {
thread th(output, i);
ss << "(" << th.get_id() << "): "; //通过get_id获取线程的id
cout << ss.str();
ss.str(""); //释放ss的缓冲区
th.join();
}
return 0;
}
运行结果如下:
通过使用join,阻塞的方式来使当前线程执行完毕后,下一个线程再开始执行。