线程启动、结束,创建线程多法、join,detach

范例演示线程运行的开始和结束

  • 程序运行起来,生成一个进程,该进程所属的主线程开始自动运行。

java主线程等待子线程结束 返回值 c主线程等待子线程结束_主线程

  • 主线程从main函数开始执行,那么我们自己创建的线程, 也需要从一个函数开始运行(初始函数),一旦这个函数运行完毕,就代表着我们这个线程运行结束(类似main函数)。
  • 整个进程是否执行完毕的标志是主线程是否执行完,如果主线程执行完毕了,就代表整个进程执行完毕了。
  • 此时,一般情况下:如果其他子线程还没有执行完毕,那么这些子线程也会被操作系统强行终止。
  • 所以,一般情况下,我们得到一个结论:如果我们想保持子线程(自己用代码创建的线程)的运行状态的话,那么就要让主线程一直保持运行,不要让主线程运行完毕。
  • 包含头文件 #include




#include #include #include using namespace std;//自己创建的线程也要从一个函数(初始函数)开始执行void myprint() {cout << "我的线程开始执行了" << endl;//...//...cout << "我的线程结束运行了" << endl;}int main(){thread mythread(myprint);mythread.join();//主线程执行std::cout << "Main Thread" << std::endl;return 0;}
#include 
#include 
#include 
using namespace std;
//自己创建的线程也要从一个函数(初始函数)开始执行
void myprint() {
cout << "我的线程开始执行了" << endl;
//...
//...
cout << "我的线程结束运行了" << endl;
}
int main()
{
thread mythread(myprint);
mythread.join();
//主线程执行
std::cout << "Main Thread" << std::endl;
return 0;
}




  • 输出
  • 有两个线程在跑,相当整 个程序的执行有两条线在同时走, 所以,可以同时干两个事, 即使一条线被堵住了,另外一条线还是可以通行的。

thread

  • thread是标准库中的类

thread mythread(myprint);

  • myprint是可调用对象。
  • 这句代码干了两件事:
  • 创建了线程,线程执行起点(入口)myprint()。
  • myprint线程开始执行。

join()

  • 加入/汇合,说白了就是阻塞,阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,然后再往下走。

//阻塞主线程并等待子线程执行完

mythread.join();

  • 主线程阻塞到这里等待myprint()执行完,当子线程执行完毕,这个join()就执行完毕,主线程就续往下走。
  • 注释掉 join() 语句,观察现象:
  • 输出

java主线程等待子线程结束 返回值 c主线程等待子线程结束_主线程_02

  • 如果主线程执行完毕了,但子线程没执行完毕,这种程序是不合格的,程序是不稳定的。
  • 一个书写良好的程序,应该是主线程等待子线程执行完毕后,自己才能最终退出。

detach()

mythread.detach();

  • detac():传统多线程程序主线程要等待子线程执行完毕,然后自己再最后退出.
  • detach:分离,也就是主线程不和子线程汇合了,你主线程执行你的,我子线程执行我的,你主线程也不必等我子线程运行完毕,我子线程也不用等你主线程运行完毕。
  • 为什么引入detach():我们创建了很多子线程,让主线程逐个等待子线程结束,这种编程方法不太好,所以引入了detach)。
  • 一旦detach()之后,与这个主线程关联的thread对象就会失去与这个主线程的关联。此时这个子线程就会理留在后台运行(主线程与跟该子线程关去联系)。
  • 这个子线程就相当于被c++运行时库接管,当这个子线程执行完成后,由运行时库负责清理该线程相关的资源(守护线程)。
  • detach() 使线程myprint失去我们的控制。
  • 一旦调用 了detach(), 就不能再用join(),否则系统会报告异常。

joinable()

  • 判断是否可以成功使用join (或者detach ()的。
  • 返回true (可以join或者detach)
  • false(不能join或者detach)。




#include #include #include using namespace std;//自己创建的线程也要从一个函数(初始函数)开始执行void myprint() {cout << "我的线程开始执行了" << endl;//...//...cout << "我的线程结束运行了" << endl;}int main(){thread mythread(myprint);if (mythread.joinable()) {cout << "1: true " << endl;}else {cout << "1: false " << endl;}mythread.detach();if (mythread.joinable()) {cout << "2: true " << endl;}else {cout << "2: false " << endl;}//主线程执行std::cout << "主线程收尾" << std::endl;return 0;}
#include 
#include 
#include 
using namespace std;
//自己创建的线程也要从一个函数(初始函数)开始执行
void myprint() {
cout << "我的线程开始执行了" << endl;
//...
//...
cout << "我的线程结束运行了" << endl;
}
int main()
{
thread mythread(myprint);
if (mythread.joinable()) {
cout << "1: true " << endl;
}
else {
cout << "1: false " << endl;
}
mythread.detach();
if (mythread.joinable()) {
cout << "2: true " << endl;
}
else {
cout << "2: false " << endl;
}
//主线程执行
std::cout << "主线程收尾" << std::endl;
return 0;
}




java主线程等待子线程结束 返回值 c主线程等待子线程结束_主线程_03

其他创建线程的手法

用类对象(可调用对象),以及一个问题范例




#include #include #include using namespace std;class AE{public:void operator()(){cout << "我的线程operator()开始执行了" << endl;//...//...cout << "我的线程operator()执行结束了" << endl;}};int main(){AE ae;thread mythread(ae); //ae: 可调用对象mythread.join();//主线程执行std::cout << "主线程收尾" << std::endl;return 0;}
#include 
#include 
#include 
using namespace std;
class AE
{
public:
void operator()(){
cout << "我的线程operator()开始执行了" << endl;
//...
//...
cout << "我的线程operator()执行结束了" << endl;
}
};
int main()
{
AE ae;
thread mythread(ae); //ae: 可调用对象
mythread.join();
//主线程执行
std::cout << "主线程收尾" << std::endl;
return 0;
}




java主线程等待子线程结束 返回值 c主线程等待子线程结束_#include_04

  • 注意这种传引用,同时使用detach的情形。




#include #include #include using namespace std;class AE{int& m_i;public:AE(int& i):m_i(i){}void operator()(){cout << "m_i的值"<< m_i << endl;}};int main(){int myi = 69;AE ae(myi);thread mythread(ae); //ae: 可调用对象mythread.detach();//主线程执行std::cout << "主线程收尾" << std::endl;return 0;}
#include 
#include 
#include 
using namespace std;
class AE
{
int& m_i;
public:
AE(int& i):m_i(i){}
void operator()(){
cout << "m_i的值"<< m_i << endl;
}
};
int main()
{
int myi = 69;
AE ae(myi);
thread mythread(ae); //ae: 可调用对象
mythread.detach();
//主线程执行
std::cout << "主线程收尾" << std::endl;
return 0;
}




  • 另一个疑问:一旦调用了detach(), 那我主线程执行结束了,我这里用的这个ae这个对象还在吗? (对象不在了)
  • 这个对象实际上是被复制(值拷贝方式)到线程中去,执行完主线程后,ae会被销毁,但是所复制的AE对象依旧存在。
  • 所以,只要这个AE类对象里没有引用,没有指针,那么就不会产生问题;。
  • 证明:




#include #include #include using namespace std;class AE{int& m_i;public:AE(int& i):m_i(i){cout << "AE 构造函数执行了" << endl;}AE(const AE& other):m_i(other.m_i) {cout << "AE 拷贝构造函数执行了" << endl;}~AE() {cout << "~AE 析构函数执行了" << endl;}void operator()(){cout << "m_i的值"<< m_i << endl;}};int main(){int myi = 69;AE ae(myi);thread mythread(ae); //ae: 可调用对象mythread.detach();//主线程执行std::cout << "主线程收尾" << std::endl;return 0;}
#include 
#include 
#include 
using namespace std;
class AE
{
int& m_i;
public:
AE(int& i):m_i(i){
cout << "AE 构造函数执行了" << endl;
}
AE(const AE& other):m_i(other.m_i) {
cout << "AE 拷贝构造函数执行了" << endl;
}
~AE() {
cout << "~AE 析构函数执行了" << endl;
}
void operator()(){
cout << "m_i的值"<< m_i << endl;
}
};
int main()
{
int myi = 69;
AE ae(myi);
thread mythread(ae); //ae: 可调用对象
mythread.detach();
//主线程执行
std::cout << "主线程收尾" << std::endl;
return 0;
}




java主线程等待子线程结束 返回值 c主线程等待子线程结束_#include_05

  • 如果使用join()

java主线程等待子线程结束 返回值 c主线程等待子线程结束_子线程_06

用lambda表达式




#include #include #include using namespace std;int main(){auto lambda1 = []() {cout << "lambda1线程执行了" << endl;//...cout << "lambda1线程结束了" << endl;};thread mythread(lambda1); //lambda1: 可调用对象mythread.join();//主线程执行std::cout << "主线程收尾" << std::endl;return 0;}
#include 
#include 
#include 
using namespace std;
int main()
{
auto lambda1 = []() {
cout << "lambda1线程执行了" << endl;
//...
cout << "lambda1线程结束了" << endl;
};
thread mythread(lambda1); //lambda1: 可调用对象
mythread.join();
//主线程执行
std::cout << "主线程收尾" << std::endl;
return 0;
}




java主线程等待子线程结束 返回值 c主线程等待子线程结束_c++主线程等待子线程结束_07

  • 方式2




#include #include #include using namespace std;int main(){auto lambda1 = []() {cout << "lambda1线程执行了" << endl;//...cout << "lambda1线程结束了" << endl;};thread mythread([](){cout << "lambda表达式线程执行了" << endl;//...cout << "lambda表达式线程结束了" << endl;}); //lambda表达式: 可调用对象mythread.join();//主线程执行std::cout << "主线程收尾" << std::endl;return 0;}
#include 
#include 
#include 
using namespace std;
int main()
{
auto lambda1 = []() {
cout << "lambda1线程执行了" << endl;
//...
cout << "lambda1线程结束了" << endl;
};
thread mythread([](){
cout << "lambda表达式线程执行了" << endl;
//...
cout << "lambda表达式线程结束了" << endl;
}
); //lambda表达式: 可调用对象
mythread.join();
//主线程执行
std::cout << "主线程收尾" << std::endl;
return 0;
}




java主线程等待子线程结束 返回值 c主线程等待子线程结束_#include_08