程序运行起来,生成一个进程,该进程所属的主线程开始自动运行;当主线程从main()函数返回,则整个进程执行完毕。
主线程从main()开始执行,那么我们自己创建的线程,也需要从一个函数开始运行(初始函数),一旦这个函数运行完毕,线程也结束运行。
整个进程是否执行完毕的标志是:主线程是否执行完,如果主线程执行完毕了,就代表整个进程执行完毕了,此时如果其他子线程还没有执行完,也会被强行终止。
线程类参数是一个可调用对象。
一组可执行的语句称为可调用对象,c++中的可调用对象可以是函数、函数指针、lambda表达式、bind创建的对象、重载()运算符的类对象。
线程创建的步骤:
- 包含头文件thread
- 写初始函数
- 在main中创建thread
创建线程代码如下:
#include
using namespace std;
//包含头文件
#include
//初始函数
void myPrint() {
cout << "我的线程开始执行!" << endl;
//......子进程过程体
cout << "我的线程执行完毕!" << endl;
}
//main中创建thread
int main(){
cout << "主线程开始执行!" << endl;
thread mythread(myPrint); //创建线程:线程执行入口myPrint(myPrint开始执行)
mythread.join(); //join()阻塞主线程,让主线程等待子线程执行完毕,让子线程和主线程汇合
cout << "主线程执行完毕!" << endl;
}
//仿函数创建线程
class MyPrint {
public:
void operator()() {
cout << "我的线程开始执行!" << endl;
//......
cout << "我的线程执行完毕!" << endl;
}
};
//main中创建thread
int main(){
cout << "主线程开始执行!" << endl;
MyPrint myPrint;
thread mythread(myPrint); //创建线程:线程执行入口myPrint(myPrint开始执行)
mythread.join(); //join()阻塞主线程,让主线程等待子线程执行完毕,让子线程和主线程汇合
cout << "主线程执行完毕!" << endl;
}
这里想提醒注意一些点:
如果使用了detach(),主线程不能再控制子线程,如果使用仿函数可能会有意料之外的情况。
thread mythread(myPrint);
创建线程的时候,传入类对象的时候,使用的是拷贝构造,因此不会出现主线程把对象myPrint释放掉,子线程会受影响的问题。但是这里使用的是浅拷贝,注意可能发生的隐藏bug。//main中创建thread
int main(){
cout << "主线程开始执行!" << endl;
auto lambdaThread = [] {
cout << "我的线程开始执行了" << endl;
//-------------
//-------------
cout << "我的线程开始执行了" << endl;
};
thread mythread(lambdaThread);//创建线程:线程执行入口lambdaThread(lambdaThread开始执行)
mythread.join();//join()阻塞主线程,让主线程等待子线程执行完毕,让子线程和主线程汇合
cout << "主线程执行完毕!" << endl;
}
我们用代码来验证,如果我们在join()前加一个打印输出:
int main(){
cout << "主线程开始执行!" << endl;
thread mythread(myPrint); //创建线程:线程执行入口myPrint(myPrint开始执行)
cout << "main" << endl; //打印main验证join功能
mythread.join(); //join()阻塞主线程,让主线程等待子线程执行完毕,让子线程和主线程汇合
cout << "主线程执行完毕!" << endl;
}
多次尝试,可以看到,有时候main打印在myPrint结束后,有时候打印在myPrint执行过程中,这说明,主进程和子进程在不断切换,join()的作用是让主进程停下来等待子进程执行结束,不然主进程执行完毕退出,子进程也会被杀死(如果此时子进程在写某些文件,中途退出会造成非常严重的后果)。
注意这里:因为涉及多线程,输出的结果难以复现,所以要多次尝试,才可能得到main的输出在myPrint输出之间的情况/
PS:尽管后面的detach支持主进程不再控制子进程,但是还是推荐这种写法,便于管控。
传统多线程,主线程要等待子线程执行结束才可以退出,但是detach的出现改变了这种情况。
- detach():分离,主线程不再与子线程汇合,不再等待子线程 。
- detach()后,子线程和主线程失去关联,驻留在后台,由C++运行时库接管。
- 只要使用了detach(),就不能再使用join(),不然会报错。
代码验证如下:
//初始函数
void myPrint() {
string nameSeed = "123456789";
for (int i = 0; i < 9; i++) {
string name = "子线程正在执行";
name += nameSeed[i];
cout << name << endl;
}
}
//main中创建thread
int main(){
cout << "主线程开始执行!" << endl;
thread mythread(myPrint); //创建线程:线程执行入口myPrint(myPrint开始执行)
mythread.detach(); //子线程与主线程分离
nstring nameSeed = "123456789";
yu for (int i = 0; i < 9; i++) {
string name = "main线程正在执行";
name += nameSeed[i];
cout << name << endl; //打印10次拖延主线程运行时间,便于查看打印效果
}
cout << "主线程执行完毕!" << endl;
}
运行结果如下:
这是一种非常标准的结果,主进程与子进程,你一句我一句打印,似乎没什么问题,但如果我们讲父进程中的循环次数改少一点,改为6,输出如下:
可以看到,子进程根本打印不完9次,仅仅执行到6,就因为主进程退出了,无法显示在屏幕上了,但是事实上,他还是会在后台运行,继续打印剩下的3个。
PS:一旦使用了detach(),子进程就已经脱离了我们的控制,也不能再次join()了,我们已经不能控制我们创建的线程的生命周期,而是由系统管理释放。
joinable()判断是否可以成功使用join()或者detach()
- 如果返回true,证明可以调用join()或者detach()
- 如果返回false,证明调用过join()或者detach(),join()和detach()都不能再调用了
if (mythread.joinable())
{
cout << "可以调用join()或者detach()" << endl;
}
else
{
cout << "不能调用join()或者detach()" << endl;
}
无论在join()之后detach();或者detach()之后join(),都是不被允许的。
joinable()就是用来判断是不是可以调用join()或者detach()。