//程序运行生成一个进程,该进程下的主线程main()函数开始自动运行
//主线程main()开始执行,自己创建的线程也需要从一个函数开始运行(也被称为初始函数),此函数运行完毕,代表该线程运行结束
//整个进程是否执行完毕的标志是 主线程main是否执行完毕,主线程main执行完毕,则进程执行完毕
//一般情况下,如果主线程已经执行完毕,其他子线程(自己创建的)还没有执行完毕,那么其他子线程也会被操作系统强行终止
//所以一般情况下,如果想保持子线程(自己创建的)运行状态,需要让主线程一直保持运行。但是有例外,后续说明
#include "stdafx.h"
#include <iostream>
#include <thread>
using namespace std;
//自己创建的线程从此函数开始运行(初始函数)
void myPrint()
{
cout << "我的线程开始执行..." << endl;
//...
//...
cout << "我的线程执行完毕..." << endl;
}
//thread:是标准库中的类
//join():阻塞并等待的作用,此处阻塞主线程,让主线程等待子线程执行完毕
//然后子线程和主线程汇合,主线程继续执行
int main(int argc, char** argv)
{
//创建线程步骤:
//a)包含头文件thread
//b)创建初始函数
//c)main中开始实现
thread myThread(myPrint); //参数:可调用对象 (此处为一个函数myPrint)
//该语句创建线程myThread 线程执行的入口为myPrint()函数,并开始执行
//此时程序中有两个线程(main和myThread)在跑,整个程序有两条线同时走
//即使一条线被堵住,另一条线可继续执行
myThread.join(); //主线程阻塞到这里等待myPrint执行完
//当myPrint执行完,join执行完毕,主线程main继续执行
cout << "hello,world!" << endl;
return 0;
}
执行结果如下图所示,由于join的阻塞和等待作用,所以显示结果为:子线程执行完后,主线程继续执行
如果未加join函数,则程序运行时出错,分析:子线程还未执行完,但主线程已经执行完,子线程被强制退出,导致程序异常(这种程序不合格)
一个良好的程序应该是主线程等待子线程执行完毕后,主线程才能退出
//传统多线程程序在主线程中要等待子线程执行完毕,然后主线程退出
//detach():分离,主线程不和子线程汇合,各自执行,主线程不等子线程运行结束,可以先运行结束
//为什么引入detach():创建了很多子线程的情况下,让主线程逐个等待子线程结束,当这种编程方法不适合时,引入detach()
//一旦detach()之后,与这个主线程关联的thread对象就会失去与主线程的关联,此时子线程就会驻留在后台运行,相当于被C++运行时库接管,当子线程执行完后,由运行时库负责清理线程资源
void myPrint1()
{
cout << "我的线程开始执行..." << endl;
//...
//...
cout << "我的线程执行完毕1..." << endl;
cout << "我的线程执行完毕2..." << endl;
cout << "我的线程执行完毕3..." << endl;
cout << "我的线程执行完毕4..." << endl;
cout << "我的线程执行完毕5..." << endl;
cout << "我的线程执行完毕6..." << endl;
cout << "我的线程执行完毕7..." << endl;
cout << "我的线程执行完毕8..." << endl;
cout << "我的线程执行完毕9..." << endl;
cout << "我的线程执行完毕10..." << endl;
cout << "我的线程执行完毕11..." << endl;
cout << "我的线程执行完毕12..." << endl;
}
int main(int argc, char** argv)
{
thread myThread(myPrint1); //创建线程并开始执行
myThread.detach(); //子线程与主线程分离
//myThread.join(); //detach()后,不能join,否则程序运行异常
cout << "hello,world 1" << endl;
cout << "hello,world 2" << endl;
cout << "hello,world 3" << endl;
return 0;
}
其中一种执行结果如下图所示,有多种执行结果,因为主线程和子线程互不影响,但是当主线程执行完毕后,进程就退出了,这时子线程会转移到后台执行,这里观察不到子线程后续执行结果
detach后,子线程myPrint1失去自己的控制,并且一旦调用了detach(),就不能再用join()
//joinable():判断现在是否可以使用join或者detach(),返回true(可以join或detach)或者false(不能使用join或detach)
int main(int argc, char** argv)
{
thread myThread(myPrint); //创建线程并开始执行
if (myThread.joinable()) //可以join或者detach
{
cout << "before detach/join:" << endl;
cout << "joinable()==true" << endl;
myThread.join(); //join操作,即阻塞主线程让主线程等待子线程执行完毕
}
else
{
cout << "before detach/join:" << endl;
cout << "joinable()==false" << endl;
}
//执行完join或者detach后
if (myThread.joinable())
{
cout << "after detach/join:" << endl;
cout << "joinable()==true" << endl;
}
else
{
cout << "after detach/join:" << endl;
cout << "joinable()==false" << endl;
}
cout << "hello,world" << endl; //主线程操作
return 0;
}
执行结果如下图所示,在join/detach之前,joinable函数返回结果为true,join操作后返回false
执行结果
//其他创建线程的方法:
//创建线程时调用对象为函数对象
class TA
{
public:
void operator()() //重载()运算符,不能有参数
{
cout << "我的线程开始operator()开始执行..." << endl;
cout << "我的线程operator()结束执行..." << endl;
}
};
int main(int argc, char** argv)
{
TA ta;
thread myThread(ta); //函数对象ta为参数:可调用对象
myThread.join(); //等待子线程执行结束
cout << "hello world" << endl;
return 0;
}
执行结果如下图所示,正常执行
//可能犯得一种bug如下:
//************ 一个坑 ***************
class TA1
{
public:
int m_i;
TA1(int& i):m_i(i)
{
cout << "TA1构造函数" << endl;
}
TA1(const TA1& ta):m_i(ta.m_i)
{
cout << "TA1拷贝构造函数" << endl;
}
~TA1()
{
cout << "TA1析构函数" << endl;
}
void operator()() //重载()运算符,不能有参数
{
cout << "m_i1的值为:" << this->m_i << endl;
cout << "m_i2的值为:" << this->m_i << endl;
cout << "m_i3的值为:" << this->m_i << endl;
cout << "m_i4的值为:" << this->m_i << endl;
cout << "m_i5的值为:" << this->m_i << endl;
}
};
int main(int argc, char** argv)
{
int i = 10;
TA1 ta(i); //会调用有参构造
thread myThread(ta); //函数对象ta为参数:可调用对象 此处调用拷贝构造函数
//myThread.detach(); //子线程与主线程分离
myThread.join();
cout << "hello world" << endl;
return 0;
}
//问题:产生不可预料的结果,因为主线程执行完后,i变量内存回收,子线程无法对i引用
//解决:可以将detach改为join等待子线程,也可以将m_i定义为int类型,则可以直接将i的值copy过来
//疑问:ta为局部变量,一旦调用了detach,若主线程先执行结束,子线程调用的这个ta还存在吗?(对象不存在)
//解答:这个对象实际上是被复制到线程中的,所以执行完主线程后,ta会被销毁,但被复制的对象依旧存在
//所以,只要TA类中没有引用、指针,就不会产生问题
如下图所示,当使用detach时,由于主线程先执行完毕后,ta对象被析构,而子线程还未执行完毕,此时拷贝的对象还未被析构,故显示只执行了一次析构,其实子线程还在后台运行,执行结果如下图所示。
如果使用join,由于主线程等待子线程执行完毕,则子线程完整执行,所以它的析构函数会执行
image.png
//创建线程时调用对象为lambda表达式
int main(int argc, char** argv)
{
auto lam = [] {
cout << "lambda表达式创建线程..." << endl;
//....
cout << "lambda thread执行结束..." << endl;
}; //lambda表达式
thread lambdaThread(lam); //创建线程并开始执行
lambdaThread.join(); //等待子线程执行完毕
cout << "hello world" << endl;
return 0;
}
执行结果如下图所示
执行结果
网友评论