理解 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 等待所有线程的退出

可以看出,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 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

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

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

相关文章

C++面试知识点总结

知识点总结 <<符号表示该语句将把这个字符串发送给cout&#xff1b;该符号指出了信息流动的路径&#xff1b;cout的对象属性包括一个插入运算符&#xff08;<<&#xff09;&#xff0c;它可以将其右侧的信息插入到流中&#xff0c;endl:重起一行。在输出流中插入en…

哈希的应用——位图

文章目录 前言1. 面试题思考2. 位图2.1 位图的概念2.2 思路讲解及代码实现结构定义构造函数set和reset接口实现set和reset测试观察test接口实现test接口测试思考 3. 位图的应用习题1习题2习题3 4. 总结5. 源码5.1 bitset.h5.2 Test.c 前言 前面的文章里我们学习了哈希表&#x…

赞奇科技参与华为云828 B2B企业节,云工作站入选精选产品解决方案

8月27日&#xff0c;由华为云携手上万家伙伴共同发起的第二届 828 B2B 企业节拉开帷幕&#xff0c;围绕五大系列活动&#xff0c;为万千中小企业带来精细化商机对接。 聚焦行业数字化所需最优产品&#xff0c;举办超1000场供需对接会&#xff0c;遍及20多个省100多个城市&…

【数据结构】动态数组(vector)的基本操作,包括插入、删除、扩容、输出、释放内存等。以下是代码的解释和注释:

这段C代码实现了一个动态数组&#xff08;vector&#xff09;的基本操作&#xff0c;包括插入、删除、扩容、输出、释放内存等。以下是代码的解释和注释&#xff1a; // 引入标准输入输出库和标准库函数&#xff0c;用于后续的内存分配和打印输出等操作 #include <stdio.…

Python小知识 - 使用Python进行数据分析

使用Python进行数据分析 数据分析简介 数据分析&#xff0c;又称为信息分析&#xff0c;是指对数据进行综合处理、归纳提炼、概括总结的过程&#xff0c;是数据处理的第一步。 数据分析的目的是了解数据的内在规律&#xff0c;为数据挖掘&#xff0c;并应用于商业决策、科学研究…

Pytorch.tensor 相关用法

Torch.tensor.backward()方法的使用举例 理解optimizer.zero_grad(), loss.backward(), optimizer.step()的作用及原理 Autograd: 自动求导 import torchatorch.randn(2,2) # tensor默认requires_gradFalse a((a*3)/(a-1)) print(a.requires_grad) print(a.grad_fn) # leaf …

运行速度高达1.8GHz可编程采集网关

今天介绍下BL304这个设备。嵌入式ARM控制器BL304系列是一款专为工业控制领域设计的坚固型工控设备。它采用NXP公司的处理器I.MX8M Mini四核64位处理器&#xff0c;搭配四核 Cortex-A53单核Cortex-M4构架&#xff0c;运行速度高达1.8GHz&#xff0c;具有高度的稳定性和可靠性。 …

从0到1学会Git(第二部分):Git的本地操作和管理

写在前面:本文介绍了在本地仓库进行文件的处理以及本地的合并等操作。 前置知识:文件可以处在三个区域&#xff0c;分别为工作区&#xff0c;暂存区和本地仓库&#xff0c;我们此文的目标即是将文件存储在本地仓库中。我们可以将文件的区域理解为&#xff0c;cpu中&#xff0c…

计算机视觉主要任务

计算机视觉&#xff1a;使用计算机及相关设备对生物视觉的一种模拟。 主要包含6大任务&#xff0c;图像分类&#xff0c;目标检测&#xff0c;目标跟踪&#xff0c;语义分割&#xff0c;实例分割&#xff0c;影像重构。 图像分类&#xff1a;根据图像信息中所反映的不同特征&am…

数据结构与算法复杂度介绍

目录 一、基本概念 二、时间复杂度 【2.1】时间复杂度概念 【2.2】大O的渐进表示法 【2.3】举例时间复杂度计算 三、空间复杂度 一、基本概念 数据结构&#xff1a;相互之间存在一种或者多种特定关系的数据元素的集合。在逻辑上可以分为线性结构&#xff0c;散列结构、树…

Redis List类型命令 - Set类型命令 - SortedSet类型命令

目录 List类型 什么是双向链表呢&#xff1f; List类型的特征&#xff1a; List的常用命令 LPUSH和RPUSH的区别&#xff1a; LPOP和RPOP的区别&#xff1a; LPUSH和RPUSH的使用 LPOP和RPOP的使用 LRANGE key star end&#xff1a;返回一段距离范围内所有的元素 BLPOP…

最小生成树Kruskal、Prim算法C++

什么是最小生成树 连通图&#xff1a; 在无向图中&#xff0c;若从顶点v1到顶点v2有路径&#xff0c;则称顶点v1和顶点v2是连通的。如果图中任意一对顶点都是连通的&#xff0c;则称此图为连通图。 生成树&#xff1a; 一个连通图的最小连通子图称作为图的生成树。有n个顶点的…

Pytorch 的基本概念和使用场景介绍

文章目录 一、基本概念1. 张量&#xff08;Tensor&#xff09;2. 自动微分&#xff08;Autograd&#xff09;3. 计算图&#xff08;Computation Graph&#xff09;4. 动态计算图&#xff08;Dynamic Computation Graph&#xff09;5. 变量&#xff08;Variable&#xff09; 二、…

【用unity实现100个游戏之8】用Unity制作一个炸弹人游戏

文章目录 前言素材开始一、绘制地图二、玩家设置三、玩家移动四、玩家四方向动画运动切换 五、放置炸弹六、生成爆炸效果七、墙壁和可破坏障碍物的判断八、道具生成和效果九、玩家死亡十、简单的敌人AI十一、简单敌人AI十二、随机绘制地图十三、虚拟摇杆 最终效果待续源码完结 …

2023年行研行业研究报告

第一章 行业概述 1.1 行研行业 行业定义为同一类别的经济活动&#xff0c;这涉及生产相似产品、应用相同生产工艺或提供同类服务的集合&#xff0c;如食品饮料行业、服饰行业、机械制造行业、金融服务行业和移动互联网行业等。 为满足全球金融业的需求&#xff0c;1999年8月…

设计模式-单例模式Singleton

单例模式 单例模式 (Singleton) (重点)1) 为什么要使用单例2) 如何实现一个单例2.a) 饿汉式2.b) 懒汉式2.c) 双重检查锁2.d) 静态内部类2.e) 枚举类2.f) 反射入侵2.g) 序列化与反序列化安全 3) 单例存在的问题3.a) 无法支持面向对象编程 单例模式 (Singleton) (重点) 一个类只…

Linux之autofs自动挂载服务

目录 Linux之autofs自动挂载服务 产生原因 安装 配置文件分析 文件路径 作用 etc/auto.master文件内容格式 挂载参数 案例 案例1 --- 服务器创建共享目录&#xff0c;客户端实现自动挂载 案例2 --- 自动挂载光盘 Linux之autofs自动挂载服务 产生原因 在一般NFS文件系…

java 从resource下载excel打不开

GetMapping("/download/template")public void template(HttpServletResponse response) throws IOException {ServletOutputStream outputStream response.getOutputStream();InputStream inputStream null;try {//从resource获取excel文件流inputStream getClas…

$attrs,$listeners

vue实现组件通信的方式有&#xff1a; 父子通信 父组件向子组件传递通过props定义各个属性来传递&#xff0c;子组件向父组件传递通过$emit触发事件 ref也可以访问组件实例跨级通信 vuex bus provide / inject $attrs / $listeners解释 $attrs / $listeners $attrs 将父组件中…

python selenium 自动化登录页面

去掉自动化标识&#xff0c;绕过js&#xff0c;绕过ip import time from selenium import webdriver from selenium.webdriver.chrome.options import Options# 去掉自动化标识&#xff0c;绕过js option Options() option.add_experimental_option(excludeSwitches, [enable…