码迷,mamicode.com
首页 > 编程语言 > 详细

二、线程创建、结束

时间:2019-07-22 19:53:51      阅读:118      评论:0      收藏:0      [点我收藏+]

标签:构造函数   auto   operator   public   成员变量   初始函数   进程   成员   c++   

一、使用函数创建线程

1、thread

主线程从main开始,我们创建的线程也要从一个函数(初始函数)开始运行,函数结束,这个线程结束;

主线程执行完毕,代表整个进程执行完毕;

如果子线程还没执行完毕,一般情况下,这些子线程会被强行终止;

1.#include <iostream>
2.#include <string>
3.#include <thread> //线程
4using namespace std;
56//创建的线程,也就是一个初始函数
7void myprint(){
8.    cout<<"1 begin" <<endl;
9.    cout<<"2 end"<<endl;
10.}
1112int main(){
13.    thread myobj(myprint);//创建线程,线程就已经开始执行了
14.    myobj.join();//阻塞主线程,让主线程等子线程执行完,然后主线程继续往下走
15//如果不写join,可能main先执行完了,子线程还没执行完,会报错
16.    cout<<"main end"<<endl;
17return 0;
18.}

技术图片

2、detach

一般情况主线程要等子线程都执行完在继续,也有例外。

detach函数:分离,主线程不用等子线程了,主线程你执行你的,子线程我执行我的,不汇合了。(一般不用detach)

原因:创建了很多子线程,让主线程逐个等待子线程结束不太好,就提出了detach。

一点detach只有,这个thread对象就失去了与主线程的联系,这些子线程就会驻留在后台运行,由c++运行时库接管,子线程结束后,运行时库负责清理线程相关的资源(守护线程)。

 1 1.#include <iostream>  
 2 2.#include <thread> //线程  
 3 3.using namespace std;  
 4 4.  
 5 5.//创建的线程,也就是一个初始函数  
 6 6.void myprint(){  
 7 7.    cout<<"1 begin" <<endl;  
 8 8.    cout<<"2 end"<<endl;  
 9 9.}  
10 10.  
11 11.int main(){  
12 12.    thread myobj(myprint);//创建线程,线程就已经开始执行了  
13 13.    myobj.detach();  
14 14.    cout<<"main end"<<endl;  
15 15.    return 0;  
16 16.}  

一旦用了detach,就不能再用join了。

3、joinable()

判断是否可以成功使用join或detach,返回true或false。

一般可以用在使用join或detach之前,用来提前先判断,如果true,就使用true或detach;否则就不能使用join或detach函数。

二、用类创建线程

用类对象创建线程,这个对象实际上是被复制到线程中的,执行完主线程后,这个类对象会被销毁,但是复制的这个对象依旧存在,直到这个子线程结束,只要你这个类对象里面没有引用、指针,就不会产生问题。

当类对象里面有引用时:

 1 #include <iostream>
 2 #include <thread> //线程
 3 using namespace std;
 4 
 5 class TA{
 6 public:
 7     int &m_i;//引用
 8     TA(int &i):m_i(i){}//构造函数,引用i
 9     void operator()(){ //可以实现将对象当函数来使用
10         cout<<"m_i的值为"<<m_i<<endl;
11     }
12 };
13 
14 int main(){
15     int a=9;
16     TA ta(a);//引用a
17     thread myobj(ta);//ta为可调对象,
18     myobj.detach();
19     //这个时候使用detach的话,有可能主线程先执行完,那么a被销毁,由于TA是引用,也就是指向了一个已经销毁的内存,会出错的,只能用join
20     cout<<"main end"<<endl;
21     return 0;
22 }

如果主线程先执行完,那么a被销毁,TA的成员变量是引用类型的,也就是子线程使用的是一个指向(引用是特殊的指针)了一个已经回收的地址,类似于野指针,就会出错,所以不要用detach。

改成join后,分析代码:创建ta对象:

  1. 创建类对象ta,构造函数被执行;
  2. 创建线程myobj,里面的ta对象复制给线程myobj,复制的ta对象构造函数执行;
  3. 执行线程,主线程等待子线程结束;
  4. 子线程myobj结束,复制的ta对象执行析构函数;
  5. 主线程继续执行 main end;
  6. main函数代码跑完了,主线程执行完毕,ta对象析构函数执行,释放内存和变量a;

三、用lambda表达式

 1 #include <iostream>
 2 #include <thread> //线程
 3 using namespace std;
 4 
 5 int main(){
 6     auto mythread = []{
 7         cout<<"我的子线程开始了"<<endl;
 8         cout<< "结束了"<<endl;
 9     };
10     thread myobj(mythread);
11     myobj.join();
12     cout<<"main end"<<endl;
13     return 0;
14 }

 

TA构造函数执行,创建线程myobj,这个ta对象时复制进去的,所以这个

 

二、线程创建、结束

标签:构造函数   auto   operator   public   成员变量   初始函数   进程   成员   c++   

原文地址:https://www.cnblogs.com/pacino12134/p/11227877.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!