• 二、线程创建、结束


    一、使用函数创建线程

    1、thread()

    创建一个线程入口函数,子线程从这个函数开始运行,函数结束,线程也就结束了。主线程执行完毕,代表整个进程执行完毕。

    如果子线程还没执行完毕,主线程先执行完了,一般情况下,这些子线程会被强行终止,这时使用join()函数,使主线程等待子线程执行完毕后,主线程与子线程会汇合,然后主线程继续走下去。

    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。

    一旦thread对象调用了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()

    thread对象调用joinable()函数,判断是否可以成功使用join或detach,返回true或false。

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

    二、用类创建线程

    thread参数除了函数名,还可以是类对象来作为线程入口。

    用类对象创建线程,这个对象实际上是被默认复制到线程中的(也就是在创建thread对象时,这个对象已经创了一个副本,在子线程中的是副本而不是本身),执行完主线程后,这个类对象会被回收,但是副本在子线程中,直到子线程结束,这个副本才会被回收,只要你这个类对象里面没有引用、指针,就不会产生问题

    当类对象里面有引用时:

    class A{
    public:
        int& m_i;
        A(int& i):m_i(i){}//构造函数
        void operator()(){//可以实现将对象当函数来使用
            cout<<"m_i的值为"<<m_i<<endl;
        }
    }
    
    int main(){
        int i=9;
        A a(i);
        thread thread1(a);//a是类对象,用类对象创建子线程
        //thread1.join();用join没问题
        thread1.detach();//会出问题!
        cout<<"main end"<<endl;
        return 0;
    }

    用detach的话,主线程与子线程分离了,有可能出现一种情况:

    • 主线程先执行完,那么a是属于主线程栈空间的,此时a被回收。但由于A构造函数是引用,所以指向了一个已经销毁的内存,类似于野指针,会出错。

    而使用join(),主线程会等子线程执行完在走,所以不会出现这个问题。

    改成join后,程序流程为:

    1. 创建类对象ta,构造函数被执行;
    2. 创建子线程的同时就开始运行了,a对象副本给了子线程,副本构造函数执行,引用的主线程里的i;
    3. 堵塞主线程,等子线程运行完;
    4. 子线程结束,a对象副本执行析构函数,子线程释放内存;
    5. 主线程继续执行;
    6. main函数代码跑完了,主线程执行完毕,a对象析构函数执行,释放内存和变量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对象时复制进去的,子线程中使用的是副本。

  • 相关阅读:
    疫情在家没事做推荐个学习的目录:怎么从一名码农成为架构师的必看知识点:目录大全(不定期更新)
    教你使用 Swoole-Tracker 秒级定位 PHP 卡死问题
    怎样深入学习php,成为php高手!?
    PHP实现简单RPC
    PHP工作岗位要求
    关于PHP在企业级开发领域的访谈
    未知及待办清单
    siege报告学习
    session&token based auth登录方式描述
    学习JWT
  • 原文地址:https://www.cnblogs.com/pacino12134/p/11227877.html
Copyright © 2020-2023  润新知