一、范例演示线程运行的开始和结束
1.thread
2.join()
3.detach()
4.joinable()
- 线程运行起来,生成一个进程,该进程所属的主线程开始自动运行。
- 主线程从main()函数开始执行,自己创建的线程,也需要从一个函数开始运行(初始函数),一旦这个函数运行完毕。该线程也结束。
- 整个进程是否执行完毕的标志:主线程是否执行完毕,如果主线程执行完毕了,那就代表整个进行执行完毕。此时,如果其他子线程还没有执行完毕,那么这些子线程也会被操作系统强行终止(一般情况)。所以,一般情况下,如果想保持子线程运行状态,则主线程应一直保持运行。
- 例外:detach(),传统程序主线程要等待子线程运行完毕,然后自己在最后退出;detach()主线程和子线程汇合,主线成也不必等待子线程运行结束。(建议主线程等待所有子线程);一旦detach()之后,与主线程关联的thread对象就会失去与主线程的关联关系,此时子线程就会驻留在后台运行(相当于被c++运行时刻接管,当子线程执行完毕后,由运行时库清理该线程相关的资源(变成守护线程))。不能detach()后再用join();joinable():判断是否可以成功使用join()或者detach(),返回true()表示可以join()或者detach();返回false不能join();
- 创建过程
- 包含头文件“thread”;
- 初始函数;
- 在main中写代码;
代码如下:
# include <thread>
#include <iostream>
using namespace std;
void my_print()
{
cout << "我的线程开始执行了" << endl;
cout << "我的线程执行完毕了" << endl;
}
int main()
{
//创建了线程,线程执行入口是 my_print()
//thread: 标准库中的类,用于创建线程;
//my_print 是一个可调用对象
thread myobj(my_print);
//阻塞主线程,让主线程等子线程执行完毕
//然后子线程和主线程汇合,主线程再往下走
//去掉后会导致程序执行混乱
//主线程阻塞在这里,等待my_print()执行完毕
myobj.join();
cout << "主程序正常退出" << endl;
}
注:代码有两条线路,两个线程在跑,所以,可以同时干两件事,即使一条线被堵住了,另外一条线还是可以通行的;如果主线程执行完毕,主线程执行完毕,程序是不稳定的;一个书写良好的程序,应该是主线程等待子线程执行完毕后,自己再终止;
二、其他创建线程的方法
1.用类以及一个问题范例
类:必须是一个可调用类对像,必须复写一下operator()()这个函数;用类创建线程,则operator()()为执行的入口点;
代码如下:
# include <thread>
#include <iostream>
using namespace std;
class TA
{
public:
void operator()()
{
cout << "我的线程开始执行了" << endl;
cout << "我的线程执行完毕了" << endl;
}
}
int main()
{
TA ta;
thread myobj(ta); //ta是可调用对象
myobj.join(); //等待子线程执行结束
cout << "主程序正常退出" << endl;
}
用例分析:
# include <thread>
#include <iostream>
using namespace std;
class TA
{
public:
int &m_i; //如果不是引用则正常,这样用是一个bug
TA(int &i):m_i(i)
{
cout << "TA()构造函数被执行了" << endl;
}
TA(const TA &ta):m_i(ta.m_i)
{
cout << "TA()拷贝函数被执行了" << endl;
}
~TA()
{
cout << "TA()析构函数被执行了" << endl;
}
void operator()()
{
cout << "m_i1 的值为:" << m_i << endl;
cout << "m_i2 的值为:" << m_i << endl;
cout << "m_i3 的值为:" << m_i << endl;
cout << "m_i4 的值为:" << m_i << endl;
cout << "m_i5 的值为:" << m_i << endl;
cout << "m_i6 的值为:" << m_i << endl;
}
}
int main()
{
int myi = 6; //主线程的局部变量,当主线程执行结束,myi被回收;
TA ta(myi); //对象也是局部的,所以主线程结束后,ta被回收;执行的析构函数析构的是主线程的ta;
//但是这个对象实际上会被复制到线程中,所以子线程可以继续运行;
//所以线程中没有引用/指针就不会产生问题;
thread myobj(ta); //ta是可调用对象
myobj.detach(); //等待子线程执行结束
// myobj.join(); //如果正常等待子线程,则会析构两次ta;
cout << "主程序正常退出" << endl;
}
2.用lambda表达式
# include <thread>
#include <iostream>
using namespace std;
int main()
{
auto mylamthread = []
{
cout << "我的线程开始执行了" << endl;
cout << "我的线程执行完毕了" << endl;
}
thread myobj(mylamthread); //ta是可调用对象
myobj.join(); //等待子线程执行结束
cout << "主程序正常退出" << endl;
}