理解 std::thread::join

news2025/1/21 3:03:07

C++多线程并发编程入门(目录)

本文用最简单易懂的实际案例,讲清楚了 join 的实际内涵,保证你过目不忘。

Hello join 示例

join 函数是我们接触C++多线程 thread 遇到的第一个函数。

比如:

int main()
{
    thread t(f);
    t.join();
}

join 用来阻塞当前线程退出

join 表示线程 t 运行起来了。但是,t 也阻碍了 main 线程的退出。

也就是说,如果 f 的执行需要 5秒钟, main也要等待5秒才能退出。

这看起来非常合理,因为 main 就应该等待 t 退出之后再退出。

main 等待所有线程

多个线程都以 join 的方式启动的时候,main 就要等到最后。

比如:

int main()
{
    thread t1(f1);
    t1.join();
    thread t2(f2);
    t2.join();
}

假如, f1 需要执行5秒, f2 需要执行 1 秒, 那么 main 就需要等待 max(5, 1) = 5 秒。

整个过程中 f1 f2 各自独立运行,谁运行谁的,互不干涉。

执行示意图

完整示例

下面的代码,main 线程 等待 first 线程 和 second 线程都退出之后再退出。

#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
using namespace std::chrono;

void first()
{
    // simulate expensive operation
    std::this_thread::sleep_for(std::chrono::seconds(5));
    cout << "first finished!" << endl;
}

void second()
{
    // simulate expensive operation
    std::this_thread::sleep_for(std::chrono::seconds(1));
    cout << "second finished!" << endl;
}

int main()
{
    auto start = std::chrono::system_clock::now();

    std::cout << "starting first helper...\n";
    std::thread helper1(first);

    std::cout << "starting second helper...\n";
    std::thread helper2(second);

    std::cout << "waiting for helpers to finish..." << std::endl;
    helper1.join();
    helper2.join();

    auto elapsed = chrono::duration_cast<chrono::seconds>(system_clock::now() - start).count();
    std::cout << "done! elapsed "<<elapsed<<" seconds.";
}

执行结果

main 等待所有线程的退出

可以看出,main 确实是等待两个线程都执行完之后才退出的。

有一个细节, 先执行完了 second 线程,后执行完了 first 线程。

这样很正常, 毕竟 second 线程耗时短(1秒),first 线程耗时长(5秒)。

所以,main 等待了 5 秒钟才退出。

线程的嵌套(join的弊端)

实际工作中,我们创建线程不大可能都在 main 函数中创建。

我们通常是在其他线程中遇到了某种事件发生,这时候才知道要赶紧创建新的线程来执行某个新任务。

比如,我们写了一个腾讯会议软件,点击开始录制按钮的时候,创建录制线程。

录制按钮的回调函数是在UI线程里执行的,也就是创建录制线程并执行录制现场这件事发生在UI线程里。不在main线程里。

示例:

int main()
{
    thread ui(ui_fun);
    ui.join();//main等待整个窗口程序关闭再退出
}

ui_fun()
{
    thread button_clicked(on_button_clicked);//创建录制线程
    button_clicked.join();//执行录制动作
}

这种情况,main 等待 ui 线程,这没什么问题。但是, ui 等待 录制线程,就会导致 ui 线程卡住。

此时你按界面上其他的按钮,就不会有任何响应。这是不应该发生的

执行示意图

main一共等待了1+5=6秒

完整示例

#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
using namespace std::chrono;

void record()
{
    // simulate expensive operation
    std::this_thread::sleep_for(std::chrono::seconds(1));
    cout << "record finished!" << endl;
}

void ui_fun()
{
    std::cout << "starting record ...\n";
    std::thread record_thread(record);
    record_thread.join();

    // simulate expensive operation
    std::this_thread::sleep_for(std::chrono::seconds(5));
    cout << "ui_fun finished!" << endl;
}

int main()
{
    auto start = std::chrono::system_clock::now();

    std::cout << "starting ui_fun ...\n";
    std::thread helper1(ui_fun);

    std::cout << "waiting for ui_fun to finish..." << std::endl;
    helper1.join();

    auto elapsed = chrono::duration_cast<chrono::seconds>(system_clock::now() - start).count();
    std::cout << "done! elapsed " << elapsed << " seconds.";
}

执行结果

参考

C++ std::thread join()的理解 - 代萌 - 博客园 (cnblogs.com)

std::thread::join - cppreference.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/966676.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

苹果Mac系统如何优化流畅的运行?提高运行速度

Mac系统的稳定性和流畅性一直备受大家称赞&#xff0c;这也是大多数人选择Mac的原因&#xff0c;尽管如此&#xff0c;我们仍不时地对Mac进行优化、调整&#xff0c;以使其比以前更快、更流畅地运行。以下是小编分享给各位的Mac优化方法&#xff0c;记得保存哦~ 一、释放被过度…

linux深入理解多进程间通信(未完)

1.进程间通信 1.1 进程间通信目的 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程资源共享&#xff1a;多个进程之间共享同样的资源。通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息&#xff0c;通知它&#xff08;它们&#xff09;发生了某种事件…

MySQL总复习

目录 登录 显示数据库 创建数据库 删除数据库 使用数据库 创建表 添加数据表数据 查询表 添加数据表多条数据 查询表中某数据 增insert 删delete 改update 查select ​ where like ​编辑 范围查找 order by 聚合函数 count max min sum avg g…

创建2个线程并执行(STL/Windows/Linux)

C并发编程入门 目录 STL 写法 #include <thread> #include <iostream> using namespace std;void thread_fun1(void) {cout << "one STL thread 1!" << endl; }void thread_fun2(void) {cout << "one STL thread 2!" <…

ip地址、LINUX、与虚拟机

子网掩码&#xff0c;是用来固定网络号的&#xff0c;例如255&#xff0c;255,255,0&#xff0c;表明前面三段必须为网络号&#xff0c;后面必须是主机号&#xff0c;那么怎么实现网络复用呢&#xff0c;例如使用c类地址&#xff0c;但是正常子网掩码是255&#xff0c;255,255,…

抽象轻松的C语言

#include <stdio.h> /* 预处理指令*/ /* 函数 */ int main() {int log 3.14;printf("hello word * %d\n easy", log);getchar();/* 获取键盘输入的字母&#xff0c;在这个程序中的作用是防止程序瞬间关闭 */return 0; } 上一篇说过&#xff0c;C程序是C语言的…

linux系统中串口驱动框架基本分析(经典)

第一&#xff1a;区分不同的终端类型 串行端口终端&#xff08;/dev/ttySn&#xff09; 串行端口终端&#xff08;Serial Port Terminal&#xff09;是使用计算机串行端口连接的终端设备。计算机把每个串行端口都看作是一个字符设备。 有段时间这些串行端口设备通常被称为终…

CXL寄存器介绍(2)- CXL DVSEC

&#x1f525;点击查看精选 CXL 系列文章&#x1f525; &#x1f525;点击进入【芯片设计验证】社区&#xff0c;查看更多精彩内容&#x1f525; &#x1f4e2; 声明&#xff1a; &#x1f96d; 作者主页&#xff1a;【MangoPapa的CSDN主页】。⚠️ 本文首发于CSDN&#xff0c…

4.0 Spring与Dubbo整合原理与源码分析

#Dubbo# 文章介绍 Dubbo中propertie文件解析以及处理原理Dubbo中@Service注解解析以及处理原理Dubbo中@Reference注解解析以及处理原理1.0 整体架构和流程 应用启动类与配置 public class Application {public static void main(String[] args) throws Exception {Annotation…

Idea中 css 、js 压缩插件会自动生成xxx.min.css、xxx.min.js文件

第一步&#xff1a;下载yuicompressor-2.4.8.jar 下载路径&#xff1a;打开搜索 YUI compressor Maven Repository: Search/Browse/Explore (mvnrepository.com)https://mvnrepository.com/ 找到点击下载即用&#xff08;如下图&#xff09; 创建文件夹&#xff0c;放入idea文…

进制转换(二进制、八进制、十六进制、十进制)

一、进制表示 二进制&#xff1a;每一位只有两种符号表示 -> 0,1 例如 (101011)₂&#xff0c;也可写作101011B&#xff0c;其中B是Binary英文的缩写。八进制&#xff1a; 每一位有8种符号表示(0~7)&#xff0c;例如(1652)₈&#xff0c;也可写作1652O&#xff0c;其中O是O…

如何查看Windows下软件使用的端口号和PID

文章目录 解决方法 解决方法 打开资源管理器&#xff1a;按下Win R&#xff0c;输入"resmon"&#xff0c;然后按Enter键 在资源监视器窗口中&#xff0c;切换到"网络"选项卡。 在"侦听端口"部分&#xff0c;你可以看到正在使用的端口号和PID…

Android——基本控件(下)(二十一)

1. 数据存储 1.1 知识点 &#xff08;1&#xff09;掌握Android数据存储的分类&#xff1b; &#xff08;2&#xff09;可以使用SharedPreferences存储数据。 1.2 具体内容 对于我们数据的存储而言&#xff0c;Android一共提供了5个数据存储的方式&#xff1a;SharedPrefe…

JS算法与树(二)

前言 二叉搜索树&#xff08;BST&#xff09;存在一个问题&#xff1a;当你添加的节点数够多的时候&#xff0c;树的一边可能会非常的深。而其他的分支却只有几层。 AVL树 为了解决上面的问题&#xff0c;我们提出一种自平衡二叉搜索树。意思是任何一个节点左右两侧子树的高度之…

NTT功能与实现

NTT的基础功用与拓展功能: 1.evaluate和interpolate evaluate的本质是选择n个点(假设f(x)的度为n)&#xff0c;计算得到其值&#xff0c;因此根据定义可以直接进行代入计算。为了加快计算的过程选取 w n w_n wn​的幂次(DFT问题即离散傅里叶变换)&#xff0c;使用FFT算法来加…

CXL.cachemem 简介(背景通道)

&#x1f525;点击查看精选 CXL 系列文章&#x1f525; &#x1f525;点击进入【芯片设计验证】社区&#xff0c;查看更多精彩内容&#x1f525; &#x1f4e2; 声明&#xff1a; &#x1f96d; 作者主页&#xff1a;【MangoPapa的CSDN主页】。⚠️ 本文首发于CSDN&#xff0c…

无涯教程-JavaScript - TDIST函数

The TDIST function replaces the T.DIST.2T & T.DIST.RT functions in Excel 2010. 描述 该函数返回学生t分布的百分点(概率)​​,其中数值(x)是t的计算值,将为其计算百分点。 t分布用于小样本数据集的假设检验。使用此函数代替t分布的临界值表。 语法 TDIST(x,deg_fr…

iOS 设置下载部分文件,如何获取完整文件的大小

在视频的需求中&#xff0c;遇到这样一个需求&#xff0c;播放一视频的时候&#xff0c;要预下载 后面10条视频&#xff0c;但是只下载后面十条视频的前面1M 实现方法 1 创建请求时设置cacheLength resource [[IdiotResource alloc] init];resource.requestURL task.request…

屋大人少,凶多吉少

在这个世界上&#xff0c;包括人在内的万事万物&#xff0c;都是有自己的气场存在的。 那么&#xff0c;人所产生的气场&#xff0c;我们称之为人气。 道法自然&#xff0c;阴阳二象&#xff0c;同样&#xff0c;人的身上也是有阴阳二气&#xff0c; 二气平衡充盈&#xff0c;会…

【Python】批量下载页面资源

【背景】 有一些非常不错的资源网站,比如一些MP3资源网站。资源很丰富,但是每一个资源都不大,一个一个下载费时费力,想用Python快速实现可复用的批量下载程序。 【思路】 获得包含资源链接的静态页面,用beautifulsoup分析页面,获得所有MP3资源的实际地址,然后下载。…