创建线程(thread)分析程序报错原因
头文件:include<thread>
理解线程的创建运行过程
你可以试着运行下面这段代码,你会发现,他肯定会报错!
#include<thread>
#include<iostream>
void task(){
std::cout<<"线程运行开始"
}
int main(){
std::thread th1(task);
}
为什么会报错?
Java里的多线程,创建好线程后,需要调用 run 或者 start 方法来启动这个线程。而 C++ 里的 thread 不需要这个过程,直接传值创建这个线程的内存后,会自动的开始运行这个线程(应该是利用的RAII特性在构造函数里面运行了这个线程的代码)。
但上面并不是报错的理由,在Java里面,线程创建之后会自动和主线程形成联系,start方法开始运行后,这个子线程会和主线程的生命周期一致,如果子线程后于主线程结束,那么就会阻塞主线程直到子线程结束才终止整个程序。当然也可以把子线程通过 setDaemon(true) 设置后,使得主线程和子线程直接的关系切断,这样主线程就不会再等待子线程了,这样就形成了守护线程。
好了,现在回归到上面的C++代码,说说为什么会发生错误。
同样,在C++里创建线程后,也会和主线程产生联系,但它并不会像Java一样主线程自动的等待子线程结束,这个等待结束的过程需要你自己去调用这个线程对应的方法。如果不去调用方法等待子线程结束,或者切断他们之间的联系,那程序就会Crash。这就是报错的原因了!
解决报错的方式:join()和detach
为了解决上面的报错问题有两种方式解决。
方法一:调用join()方法进行合并
由于主线程和子线程之间有联系,我们如果需要正常执行完这个程序,则需要保证整个线程一并结束或者是切断联系。
join() 方法的调用就是等待子线程和主线程汇聚,产生的效果就是主线程被阻塞,直到子线程结束运行,阻塞停止。
join在这里是汇聚汇集之意,你可以想象有多根线,最终结束的时候这几根线需要汇聚到一起,然后全部的线程就结束了,整个程序正常退出!
代码如下:就仅仅在最后加入了一行join代码,程序bug被解决!
#include<thread>
#include<iostream>
void task(){
std::cout<<"线程运行开始";
}
int main(){
std::thread th1(task);
th1.join();
}
方法二:调用detach()方法分离线程联系
前面也讲到,由于主线程和子线程之间的联系,导致主线程需要照顾子线程。那么detach方法的调用就是切断这个联系。调用了这个方法后,主线程不会再等待子线程执行结束,而是直接正常结束,而子线程是否执行完成和我主线程没有任何关系了。
调用这个方法后的线程,可以理解为守护线程了。这种情况下内存安全要引起重视,如果子线程用到了主线程的资源,这个情况下将会导致 指针悬空 这是一个非常严重的内存安全问题!
代码如下:
#include<thread>
#include<iostream>
void task(){
std::cout<<"线程运行开始";
}
int main(){
std::thread th1(task);
th1.detach();
}
|