理解 std::thread::join
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 operationstd::this_thread::sleep_for(std::chrono::seconds(5));cout << "first finished!" << endl;
}void second()
{// simulate expensive operationstd::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 确实是等待两个线程都执行完之后才退出的。
有一个细节, 先执行完了 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 线程卡住。
此时你按界面上其他的按钮,就不会有任何响应。这是不应该发生的。
执行示意图
完整示例
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
using namespace std::chrono;void record()
{// simulate expensive operationstd::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 operationstd::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
相关文章:
理解 std::thread::join
C多线程并发编程入门(目录) 本文用最简单易懂的实际案例,讲清楚了 join 的实际内涵,保证你过目不忘。 Hello join 示例 join 函数是我们接触C多线程 thread 遇到的第一个函数。 比如: int main() {thread t(f);t.…...
C#循环定时上传数据,失败重传解决方案,数据库标识
有些时候我们需要定时的上传一些数据库的数据,在数据不完整的情况下可能上传失败,上传失败后我们需要定时在重新上传失败的数据,该怎么合理的制定解决方案呢?下面一起看一下: 当然本篇文章只是提供一个思路࿰…...
R语言图形的组合( par(),layout(),par(fig()) )
引入d.class进行画图 > d.class<-read.csv("D://class.csv",header T) > attach(d.class) > opar<-par(no.readonly TRUE)非常简单的数据,需要可自取 链接:https://pan.baidu.com/s/1zNx5z9JsaaRqFueRgGY3mQ 提取码&#x…...
如何为 Flutter 应用程序创建环境变量
我们为什么需要环境变量? 主要用于存储高级机密数据,如果泄露可能会危及您产品的安全性。这些变量本地存储在每个用户的本地系统中,不应该签入存储库。每个用户都有这些变量的副本。 配置 在根项目中创建一个名为 .env 的文件夹(…...
「C++程序设计 (面向对象进阶)」学习笔记・一
0、引言 本专栏的系列文章是在学习 北京邮电大学 崔毅东 老师的《C程序设计 (面向对象进阶)》课程过程中整理的。欢迎前往专栏了解更多相关内容~ 😀 有关于现代 C 的基本介绍,请前往《现代C基本介绍》! 🔔 先决条件 本专栏的系列…...
Leetcode125. 验证回文串
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字符。 给你一个字符串 s&…...
【Yellowbrick】特征可视化分析
Yellowbrick特征可视化分析 ⭐Yellowbrick⭐特征分析可视化⭐Rank1D⭐Rank2D ⭐Yellowbrick Yellowbrick是一个用于可视化机器学习模型和评估性能的Python库。它提供了一系列高级可视化工具,帮助数据科学家和机器学习从业者更好地理解、调试和优化他们的模型。 它在…...
Android大厂需要刷的(999道)面试题
想必大家都在为今年的金九银十做准备,今年也是最为艰难的一年。作为程序员从未感觉到如此艰难,身边不是被辞退就是找不到工作。先不说2023年应届生毕业即失业,作为开发15年的老Android程序员,现在也在和300个人挣一个岗位。 肉少…...
Pycharm中出现ImportError:DLL load failed:找不到指定模块的解决方法
不论搭建什么工程,运行什么文件,只要在Pycharm中出现ImportError: DLL load failed: 找不到指定的模块这样的问题,以下方法都适用!!! 一、问题描述 我在使用pycharm连接webots,用python控制机…...
Java设计模式:四、行为型模式-08:策略模式
文章目录 一、定义:策略模式二、模拟场景:策略模式三、违背方案:策略模式3.0 引入依赖3.1 工程结构3.2 优惠券折扣计算类3.3 单元测试 四、改善代码:策略模式4.1 工程结构4.2 策略模式结构图4.3 优惠券折扣实现4.3.1 定义优惠券接…...
ICCOA蓝牙数字车钥匙2.0
近期,ICCOA智慧车联开放联盟宣布,由小米、vivo、OPPO、长安、深蓝、吉利、极氪、比亚迪、北汽、蔚来、零跑、雪球、瓶钵、融卡等企业联合参与制定的ICCOA蓝牙数字车钥匙2.0标准(简称DK2.0),于2023年9月1日正式发布实施…...
ArcGIS土地利用程度综合指数分析
成图展示: 土地利用程度综合指数 第一步 准备数据 使用的数据为2010年河南省土地利用类型数据与其行政区划县级数据(为了节省操作,这里使用上次实验的部分数据[1],各土地利用类型已被提取) 第二步 面积统计 水域为例…...
服务端请求伪造(SSRF)及漏洞复现
文章目录 渗透测试漏洞原理服务端请求伪造1. SSRF 概述1.1 SSRF 场景1.1.1 PHP 实现 1.2 SSRF 原理1.3 SSRF 危害 2. SSRF 攻防2.1 SSRF 利用2.1.1 文件访问2.1.2 端口扫描2.1.3 读取本地文件2.1.4 内网应用指纹识别2.1.5 攻击内网Web应用 2.2 SSRF 经典案例2.2.1 访问页面2.2.…...
v-model和v-bind
v-model,它其实就是一个语法糖,作用就是双向绑定表单控件(radio, text,address,email,select,checkbox,textarea) v-bind(简写形式:value值),用于绑定属性值,只能实现数据的单项绑定。 <template> <div>…...
详细介绍 弹性盒子(display:flex)
文章目录 什么是弹性盒子 如何使用弹性盒子flex系列flex-direction 对齐方向 水平对齐垂直对齐flex-wrap 换行flex-flowflex模型说明容器的属性 justify-content X轴对齐方式align-content Y轴对齐方式总结属性值Y轴对齐的另外一种:align-itemsalign-content和alig…...
Docker使用数据卷挂载进行数据存储与共享
一、挂载和数据卷 在 Docker 中,挂载(Mounting)和数据卷(Data Volumes)是用于在容器和宿主机之间共享数据的机制。 挂载:将宿主机文件系统中的目录或文件与容器中的目录或文件进行关联的过程。数据卷&…...
[力扣146. LRU 缓存 ](https://leetcode.cn/problems/lru-cache/description/)
力扣146. LRU 缓存 使用LinkedHashmap(HashMap的子类,能够记住插入数据的顺序). LRU是Lease Recently User的缩写,意思是最近 最少使用。比如设计一个文件缓存系统,每个文件有自己的大小和访问时间,文件缓存系统有总的大小&…...
Mysql存储引擎
目录 一、前言 二、存储引擎 1、InnoDB存储引擎 1.1、简介 1.2、优势 1.3、使用方法 1.4、性能 2、MyISAM存储引擎 2.1、优势 2.2、使用方法 2.3、性能 3、MEMORY存储引擎 4、MyISAM 三、比较 四、总结 一、前言 MySQL是开放源代码的关系型数据库管理系统&…...
算法通关村-----数组实现加法专题问题解析
数组实现整数加法 问题描述 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。你可以假设除了整数 0 之外,这个整数不会以零开头。详见leetcode66 问题…...
倒排表的压缩算法
For压缩算法 这是倒排表的一种压缩算法。 还是那个问题,如果"小米" 这个词项,在多文档里都有,则就会导致倒排表很大,这时候就会设计到了压缩算法,这里说的是,倒排表。 那末我们来看看 for压缩…...
listmonk数据库查询缓存键命名规范:一致性与可读性
listmonk数据库查询缓存键命名规范:一致性与可读性 在高性能自托管邮件列表管理器listmonk中,数据库查询缓存是提升系统响应速度的关键组件。本文将深入解析listmonk项目中数据库查询缓存键的命名规范,探讨如何通过一致性的命名规则和良好的…...
【C#vsPython·第一阶段】 Python 的运算符,有些地方真的“骚“
在 C# 里判断一个数在 0 到 10 之间,你得写 x > 0 && x < 10。 在 Python 里?直接写 0 < x < 10。对,就这么简单,编译器...哦不,解释器不会报错。 当我第一次看到这个写法的时候,我心…...
OpenClaw自动化配置实战:从入门到精通,打造高效工作流
1. 项目概述与核心价值最近在折腾开源自动化工具,发现了一个宝藏仓库:ShuyuZ1999/awesome-openclaw-configs。这个项目乍一看名字有点长,但核心价值非常明确——它是一个专门为开源自动化工具OpenClaw收集、整理和分享高质量配置文件的集合。…...
终极HiveWE魔兽地图编辑器:如何用现代化工具打造专业级游戏地图
终极HiveWE魔兽地图编辑器:如何用现代化工具打造专业级游戏地图 【免费下载链接】HiveWE A Warcraft III world editor. 项目地址: https://gitcode.com/gh_mirrors/hi/HiveWE 还在为传统魔兽争霸III地图编辑器缓慢的加载速度和繁琐的操作而烦恼吗࿱…...
Linux只读挂载保护排查方法
Linux只读挂载保护排查方法本文面向具备一定 Linux 基础的技术人员,围绕只读挂载保护展开,重点讨论写入隔离、配置保护和异常诊断。在中级运维和系统管理工作中,这类主题常常与配置变更、资源状态、权限边界、自动化任务和业务影响交织在一起…...
树莓派驱动MAX31855热电偶传感器:从SPI通信到高精度测温实践
1. 项目概述:从热电偶到Python读数在嵌入式开发、工业监控或者任何需要精确测温的项目里,热电偶(Thermocouple)往往是工程师们的首选传感器。它结构简单、皮实耐用,而且测温范围能从零下两百多度一直覆盖到上千度&…...
免费网盘直链下载助手:一站式解决九大平台文件下载难题
免费网盘直链下载助手:一站式解决九大平台文件下载难题 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼…...
构建本地化多链资产追踪器:从API聚合到数据可视化实践
1. 项目概述与核心价值最近在折腾一个挺有意思的小工具,起因是发现很多朋友在管理自己的数字资产时,尤其是那些基于区块链的Token,常常会陷入一种“信息孤岛”的状态。钱包地址散落在各处,不同链上的资产变动需要一个个去浏览器查…...
从脚本到爆款:ElevenLabs广告配音全流程SOP(含品牌人设音色锚定表+情绪曲线映射表)
更多请点击: https://intelliparadigm.com 第一章:从脚本到爆款:ElevenLabs广告配音全流程SOP(含品牌人设音色锚定表情绪曲线映射表) ElevenLabs 已成为全球增长最快的 AI 语音平台之一,其高保真、低延迟、…...
避开这3个坑,你的STM32F103+LoRa+阿里云项目才能跑得稳
STM32F103LoRa阿里云物联网项目稳定性优化实战指南 在物联网设备开发中,稳定性往往是区分业余原型与工业级产品的关键分水岭。许多开发者能够快速搭建起STM32F103与LoRa模块的基础通信框架,并实现阿里云物联网平台的数据上传,却在长期运行中频…...
