【C++11多线程并发编程】CH2_线程构建,启动和结束的方法

本博文由 youngpan1101 出品,转载请注明出处。 
文章链接:
作者: 宋洋鹏(youngpan1101) 
邮箱: yangpeng_song@163.com

ps:该博文是《王健伟老师的:c++11多线程并发视频教程》的课后笔记。

目录

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

其他创建线程的方法

类对象_创建线程

lambda表达式_创建线程


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

当一个程序运行起来,进程就开始执行,该进程所属的主线程也会自动开始运行。

主线程是从main()开始执行,主线程是否执行完毕决定了整个进程的执行进度,而我们另外构建的线程也需要从一个函数开始运行,一旦该函数运行完毕,意味着我们构建的线程也结束运行。若主线程执行完毕,而其他子线程还没有执行完毕,那这些子线程也会被操作系统强行终止。

结论:若想要保持子线程的运行状态,则建议让主线程一直保持运行,让主线程去等待子线程的结束。(后面接触到detach方法可以让子线程在后台运行,但是在大型项目中会有不可预料的bug,所以这里是建议)

join():加入/汇合,即阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,然后主线程再往下执行。

#include <iostream>
#include <string>

#include <thread>      //增加头文件

using namespace std;

//自己构建线程的入口函数
void myFunc()  
{
   cout << "我的线程开始执行了。。。" << endl;
   // ...
   cout << "我的线程执行完毕了。。。" << endl;
}

int main()
{
    std::cout << "Hello World!\n";
    thread myThreadObject(myFunc);  //1)创建了线程,线程执行入口为 myFunc(); 2)myFunc线程开始执行
    myThreadObject.join();  // join():加入/汇合,即阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,然后主线程再往下执行
    cout << "主线程安全退出!!!" << endl;

    return 0;
}

上面demo中如果主线程执行完毕了,但子线程没执行完毕,这种程序是不稳定的,所以用了 join() 来阻塞主线程并等待myFunc子线程执行完毕。 

若将 join() 函数注释掉,运行会报异常,因为主线程执行完毕后子线程还在运行中。

detach():分离,主线程和子线程是相互分离的状态,不存在等待谁执行完毕的说法。一旦detach()之后,与该主线程关联的thread对象就会失去与主线程的关联,该子线程会驻留在后台运行,也就是说detach()会使线程myFunc失去控制。

另外,若调用了detach(),就不能用join(),否则系统会报异常。

#include <iostream>
#include <string>

#include <thread>      //增加头文件

using namespace std;

//自己构建线程的入口函数
void myFunc()  
{
    cout << "我的线程开始执行了。。。" << endl;
    // ...
    cout << "我的线程执行完毕了。。。" << endl;
}

int main()
{
    std::cout << "Hello World!\n";

    thread myThreadObject(myFunc);  //1)创建了线程,线程执行入口为 myFunc(); 2)myFunc线程开始执行
    //myThreadObject.join();  // join():加入/汇合,即阻塞主线程

    myThreadObject.detach();

    cout << "主线程安全退出!!!1" << endl;
    cout << "主线程安全退出!!!2" << endl;
    cout << "主线程安全退出!!!3" << endl;
    cout << "主线程安全退出!!!4" << endl;
    cout << "主线程安全退出!!!5" << endl;
    cout << "主线程安全退出!!!6" << endl;
    cout << "主线程安全退出!!!7" << endl;
    cout << "主线程安全退出!!!1" << endl;
    cout << "主线程安全退出!!!2" << endl;
    cout << "主线程安全退出!!!3" << endl;
    cout << "主线程安全退出!!!4" << endl;
    cout << "主线程安全退出!!!5" << endl;
    cout << "主线程安全退出!!!6" << endl;
    cout << "主线程安全退出!!!7" << endl;

    return 0;
}

joinable():判断该线程是否为可执行线程。

通常以下几种情况会导致线程成为 not-joinable:

  1. 由 thread 的缺省构造函数构造而成( thread() 没有参数);
  2. 该 thread 被 move 过(包括 move 构造和 move 赋值);
  3. 该线程调用过 join 或者 detach。
#include <iostream>
#include <string>

#include <thread>      //增加头文件

using namespace std;

//自己构建线程的入口函数
void myFunc()  
{
    cout << "我的线程开始执行了。。。" << endl;
    // ...
    cout << "我的线程执行完毕了。。。" << endl;
}

int main()
{
    thread nonParamThread; //thread()没有参数
    thread myThreadObject(myFunc);  //1)创建了线程,线程执行入口为 myFunc(); 2)myFunc线程开始执行
    //myThreadObject.join();  // join():加入/汇合,即阻塞主线程

    cout << "Joinable after construction:" << endl;  
    cout << "nonParamThread: " << nonParamThread.joinable() << endl;  
    cout << "myThreadObject: " << myThreadObject.joinable() << endl;

    if (nonParamThread.joinable())	
        nonParamThread.detach();
    if (myThreadObject.joinable())	
        myThreadObject.detach();

    cout << "Joinable after joining:" << endl;
    cout << "nonParamThread: " << nonParamThread.joinable() << endl;
    cout << "myThreadObject: " << myThreadObject.joinable() << endl;

    return 0;
}

  

其他创建线程的方法

类对象_创建线程

#include <iostream>
#include <string>

#include <thread>      //增加头文件

using namespace std;

class myClass
{
public:
    void operator()()  //重载,不能带参数
    {
        cout << "我的线程 myClass::operator() 开始执行了。。。" << endl;
        //...
        cout << "我的线程 myClass::operator() 结束执行了。。。" << endl;
    }
};

int main()
{
    myClass myClassObj;
    thread myThreadObj(myClassObj);
    myThreadObj.join();  //等待子线程执行结束

    cout << "主线程安全退出了!!!" << endl;

    return 0;
}

C/C++ - 类中成员变量是引用 【Link

若类对象的方法创建线程中,是通过引用来传参,而又用detach()函数,则会出现主线程提前结束,会回收局部变量,而myClass::m_i 又在被读取,最终导致意想不到的异常(!!!这里也是重申尽量不要用detach()!!!),具体代码如下:

#include <iostream>
#include <string>

#include <thread>      //增加头文件

using namespace std;

class myClass
{
public:
    int& m_i;    //成员变量是引用

    myClass(int& i) :m_i(i)
    {
        cout << "myClass 构造函数执行了..." << endl;
    }

    myClass(const myClass& myclass) :m_i(myclass.m_i)
    {
        cout << "myClass 拷贝构造函数执行了..." << endl;
    }

    ~myClass()
    {
        cout << "~myClass 析构函数执行了..." << endl;
    }

    void operator()()  //不能带参数
    {
        //cout << "我的线程 myClass::operator() 开始执行了。。。" << endl;
        //...
        //cout << "我的线程 myClass::operator() 结束执行了。。。" << endl;
        cout << "m_i = " << m_i << endl;
    }
};

int main()
{
    int myIntVal = 8;    //myIntVal是局部变量,主线程接受后,该变量会被回收
    myClass myClassObj(myIntVal);  

    //myClassObj会被复制到线程中,当主线程被销毁,myThreadObj还是可以正常运行,但是不能包括引用、指针等传参
    thread myThreadObj(myClassObj);

    //myThreadObj.join();  //等待子线程执行结束
    myThreadObj.detach();  //子线程和主线程分离

    for (int i = 0; i < 24; i++)
        cout << "主线程安全退出了!!!" << i << endl;

    return 0;
}

lambda表达式_创建线程

int main()
{
    //...
    auto mylamThread = [] {
        cout << "我的线程 mylamThread 开始执行了。。。" << endl;
        //...
        cout << "我的线程 mylamThread 结束执行了。。。" << endl;
    };
    thread myThreadObj3(mylamThread);
    myThreadObj3.join();
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值