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

2023-05-16

本博文由 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();
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • 流量变现的10种方式

    在互联网飞速发展的今天 xff0c 流量就等于金钱 xff0c 流量越大意味着赚的钱越多 流量如何变现呢 xff1f 以下10种方式可供参考 xff1a 打造个人品牌变现 xff1a 通过写文章或发布短视频 xff0c 提高自己的知名度 x
  • ubuntu 下 .7z 文件解压时,子文件夹内的内容被解压到根文件夹问题

    7z e log4cplus 2 0 8 7z o home wukai Documents log4cplus 参数使用 e 时 xff0c 会导致子文件夹内的内容被解压到根文件夹 xff0c 导致子文件夹没东西 xff0c 且覆盖了根文
  • configure: error: cannot find sources (src/logger.cxx) in . or ..

    配置的时候 xff0c 找不到文件 查看下src文件夹下是不是没有这个文件 xff0c 如果没有 xff0c 可能性有一下两个 1 解压的时候出错 xff0c 导致此文件被解压到其他文件夹 xff1b xff08 参考https mp cs
  • windows下python下载及安装

    下载python安装包 进入python官网 xff1a https www python org 鼠标移动到 Downloads gt 34 Windows 34 上 xff0c 可以看到最新版本是3 11 3版本 点击 Windows
  • 修改环境变量

    点击 windows 按钮 xff0c 输入 环境 xff0c 点击右侧的 编辑系统环境变量 点击 环境变量 按钮 按如下顺序将python添加到环境变量中 然后再把所有弹框的确定按钮都点下
  • windows下创建python文件

    1 打开python IDLE 按下 windows 按钮 xff0c 输入python xff0c 单击 IDLE Python 3 9 64 bit 点击File gt New File 新文件未命令 xff0c 内容空 随意编辑代码
  • python代码注释

    在python中 xff0c 存在三种类型的注释 xff1a 单行注释 多行注释和中文声明注释 1 单行注释 xff08 在需要注释的内容前面加 xff09 注释内容 2 多行注释 xff08 将要注释的内容包含在 或者 内 xff09 3
  • python3.9.13 IDLE设置缩进值

    Options gt 34 Configure IDLE 34 gt 34 Windows 34 Indent spaces 即是缩进值
  • unindent does not match any outer indentation level

    python运行时 xff0c 报错 unindent does not match any outer indentation level 有某行的缩进和其他行不匹配
  • python分行

    方式一 xff1a print 34 123 34 34 456 34 方式二 xff1a print 34 wer asd 34 输出 123456 werasd
  • python命名规范

    1 模块名 xff1a 尽量短小 xff0c 全部小写 xff0c 可以使用下划线分隔多个字母 如 xff1a func 1 func 2 2 类名 xff1a 采用单词首字母大写的方式 如 xff1a Student Teacher 3
  • YOLOv5之autoanchor看这一篇就够了

    简单粗暴 xff0c 废话也不罗嗦了 xff0c 学习目的就是解决下面三个问题 xff0c 1 默认anchor t设置为4 xff0c 这个参数如何调整 xff1f 有没有必要调整 xff1f xff08 首先网上很多说这个参数是长宽比是
  • 反转一个长字符串中的子字符串

    第一次练习写博客 xff0c 记录下自己感觉满意的成果吧 include lt stdio h gt include lt string h gt bool findPosition char sur char dst int amp st
  • c中全局变量,全局结构体使用

    1 在A 中定义的函数 xff0c 如何在 B 中调用 xff1f 如果有头文件 xff0c 在头文件中声明 xff0c 在B 文件中 include 头文件就可以了 如果是在 c 文件中声明的 xff0c 在 B 中加 extent 声明
  • Vue3展示Markdown内容

    起因 想要搭建一个个人网站 xff0c 然后在网站上展示个人信息以及平时学习或者使用框架的一些内容 所以需要一个能够将markdown内容转化到页面上展示 xff08 就类似于github或者各大博客网站 xff09 个人网站是vue3 x
  • debian linux 添加永久环境变量

    写在前面的话 搜索linux添加环境变量 xff0c 网上已经有很多的教程 xff0c 本来就几个命令还是把我搞的好惨 xff0c 几个坑大牛们不指出来 xff0c 我这小白就卡在里面了 xff0c 写下血泪史供参考 关于环境变量 expo
  • CLion、IDEA、Pycharm等用WSL访问不了环境变量的解决方案——更新于2021.12

    目录 相关文献PowerShell解决方案 博主全网搜索过很多教程 xff0c 各种碰壁不成功 xff0c 最终使用了PowerShell成功的 本文将介绍PowerShell的成功方法和几个替代方案 博主使用WSL是Ubuntu 20 0
  • Linux下安装xrdp实现远程桌面

    使用rdp协议访问远程Linux桌面 一般情况下 xff0c 如果需要登陆远程Linux系统 xff0c 我们会使用ssh telnet来完成 xff0c 如果需要登陆到远程Linux系统的桌面环境 xff0c 我们可能会使用VNC VNC
  • 树莓派——xrdp win10远程登录以及蓝屏问题

    1 安装xrdp 使用Putty命令行输入以下命令 sudo apt get install xrdp sudo apt get install tightvncserver xrdp 安装完成后 xff0c 重启xrdp服务器 sudo
  • 使用lnmp安装Nextcloud出现404问题解决方法

    最新消息 特大消息特大消息 xff0c 由于答主解决不了后续出现的WEBDAV接口错误问题 xff0c 因此更改了安装方式 61 61 61 61 61 DOCKER xff01 装完之后感慨一下 xff0c docker大法真好 参考教程

随机推荐