商业网站建设惠州网站建设

湖南亚彦网络科技有限公司 2026/09/09 19:37:41


一、线程等待

#include <iostream> #include <pthread.h> #include <cstdio> #include <stdlib.h> #include <ctime> #include <unistd.h> #include "Task.hpp" #include <vector> void* Routine(void* args) { std::string name = static_cast<const char*>(args); while(true) { std::cout << "new thread" << name << std::endl; sleep(5); break; } return (void*)10; } //线程等待 int main() { pthread_t tid; pthread_create(&tid,nullptr,Routine,(void*)"thread_1"); //等待线程退出,否则会出现类似于进程僵尸问题 void* retval = nullptr; int n = pthread_join(tid,&retval); if(n == 0)//等待成功 { std::cout << "join success: " << (long long)retval << std::endl; } return 0; }

注意:使用 ps -aL 是查不到线程退出时的僵尸状态的,因为 ps -aL 查的是系统级的轻量级进程,在内核中已经把这个线程释放了,但是线程管理的相关消息在 pthread 库内部中还存在。

问题:pthread_join 获取到的退出消息,为什么没有退出信号?为什么没有进行异常分析

答:新线程出异常,进程全部退出,线程没机会 join 成功,所以线程不需要关系异常。

注意:Routine 的返回值不一定是整数,他可以是一个字符串、类对象等。

#include <iostream> #include <pthread.h> #include <cstdio> #include <stdlib.h> #include <ctime> #include <unistd.h> #include "Task.hpp" #include <vector> void* Routine(void* args) { std::string name = static_cast<const char*>(args); while(true) { std::cout << "new thread" << name << std::endl; sleep(1); } } //线程等待 int main() { pthread_t tid; pthread_create(&tid,nullptr,Routine,(void*)"thread_1"); //等待线程退出,否则会出现类似于进程僵尸问题 sleep(5); pthread_cancel(tid);//主动杀掉指定线程 void* retval = nullptr; int n = pthread_join(tid,&retval); if(n == 0)//等待成功 { std::cout << "join success: " << (long long)retval << std::endl; } return 0; }

如果是主线程主动杀掉线程时,线程的退出消息为 -1(PTHREAD_CANCELED);

二、分离线程

默认情况下,新创建的线程是 joinable 的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。

如果不关心线程的返回值,join 是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。此时把线程设置成分离状态就行。

#include <iostream> #include <pthread.h> #include <cstdio> #include <stdlib.h> #include <ctime> #include <unistd.h> #include "Task.hpp" #include <vector> void* Routine(void* args) { std::string name = static_cast<const char*>(args); int cnt = 5; while(cnt--) { std::cout << "new thread" << name << std::endl; sleep(1); } return (void*)10; } //线程等待 int main() { pthread_t tid; pthread_create(&tid,nullptr,Routine,(void*)"thread_1"); sleep(2); pthread_detach(tid);//把线程设置分离状态 void* retval = nullptr; int n = pthread_join(tid,&retval); if(n == 0)//等待成功 { std::cout << "join success: " << (long long)retval << std::endl; } else { sstd::cout << "join erroe: " << n << std::endl; } return 0; }

如果把线程设置成分离状态,主线程还要等待线程的话,必然会等待失败。

注意:一旦线程被设置成分离状态,则主线程不能提前退,甚至主线程是个死循环。既然把线程分离了,但是一旦线程出了问题,例如:除0,野指针等,还是会导致整个进程崩掉。

三、线程 ID 和进程地址空间布局

首先 pthread 库也是库,要加载到内存,进而映射到当前进程的虚拟地址空间,以便支持线程控制,在之前的我们可以知道线程的 id 值是一个非常大的数字,现在我可以明确的是线程的 id 值就是一个地址!线程既然可以有多个,那么有的线程正在运行、正在退出、正在分离等,这么多的线程肯定是要被管理起来的,怎么管理?先描述,再组织;注意:这里的线程概念在 Linux 内核中是没有体现出来的,内核里只有轻量级进程的概念,所以线程概念只有在 pthread 库里面体现!所以描述线程,使用 stuct Tcb 来描述,不是在 Linux 内核中描述,而是在 pthread 库里面描述,而组织请看下图:

我们每创建一个线程,在虚拟地址空间里面的 pthread 库就会创建该线程的属性信息,这些属性信息包括:struct pthread 结构体(这个结构体就是上面说的 Tcb)、线程局部存储、线程栈。而线程 id 值或者说 tid 就是这个属性信息的起始地址!!因为每个线程的属性信息在虚拟地址空间上是连续的,所以我们可以联想成是一个数组来管理这些线程的属性信息。在 struct pthread 结构体里面有个变量 void * result 这个变量来存储线程退出的信息,也就是说当 Routine 函数的返回值起始就是赋值给这个变量 result ,而 pthread_join 获取到线程退出的信息也就是把这个变量 result 赋值给我们的传过去的变量。

我们创建线程的底层是调用 clone 系统调用,而 clone 函数是用来创建轻量级进程或者进程的,在 clone 中如果不用创建虚拟地址空间、页表等数据结构,那么就是要创建轻量级进程,即:只创建 PCB ,那么我们可以得出一个结论:每创建一个线程都会在系统层面上有对应的 PCB ,也就是说:struct pthread : struct task_struct = 1 :1,这个称为:1:1 式的用户及线程;而 PCB 承担线程的调度、保存轻量级进程的上下文数据等作用,而 struct pthread 结构体是在库里面描述线程的属性,只是 PCB 承担了线程的大部分属性,所以 struct pthread 里面的属性才会这么少。所以线程退出时,PCB 是直接释放的,所以我们使用 pa -aL 来查线程是查不到的,但是 struct pthread 还存在,所以我们要等待线程释放掉这个 struct pthread 结构体以及该线程的线程局部存储、线程栈。struct pthread 和 线程局部存储、线程栈我们叫做线程的描述信息。

线程局部性存储:

#include <iostream> #include <pthread.h> #include <cstdio> #include <stdlib.h> #include <ctime> #include <unistd.h> #include "Task.hpp" #include <vector> //此时还没有就行线程局部存储 pid_t id = 0; void* Routine(void* args) { std::string name = static_cast<const char*>(args); while (true) { std::cout << "new thread id: " << id << std::endl; id++; sleep(1); } return nullptr; } int main() { pthread_t tid; pthread_create(&tid,nullptr,Routine,(void*)"thread_1"); while (true) { std::cout << "main thread id : " << id << std::endl; sleep(1); } pthread_join(tid,nullptr); return 0; }

上面的出现这张情况的原因:因为线程局部性存储是给每个线程开辟一段栈空间,也就是上面这个 id 值的地址在每个线程的中的虚拟地址是不一样的:

注意:mmap 区域其实就是虚拟地址空间的共享区;上面图片中的线程栈是专门给线程使用的,而上上张图里面的主线程栈是给主线程使用的。

线程局部性存储:只能用来局部性存储内置类型,常见的是整型;

线程局部性存储的意义:可以让不同的线程用同样的变量名,访问不同的内存块,各自访问各自的局部存储。

注意:线程局部性存储这个工作/过程是编译器做的。

四、C++ 的多线程(代码示范)

#include <iostream> #include <unistd.h> #include <thread> void Routine(int cnt) { while (cnt--) { std::cout << "new thread : " << cnt << std::endl; sleep(1); cnt--; } } int main() { std::thread t(Routine,10);//创建线程 while(true) { std::cout << "main thread" << std::endl; sleep(1); } t.join();//线程等待 return 0; }
TestThread:TestThread.cc g++ -o $@ $^ -std=c++11 .PHONY:clean clean: rm -f TestThread

使用C++来编写线程,在 Linux 中能跑,而且把这份代码复制到 Windows 平台下也能跑,这证明 C++ 具有很强的跨平台性(把所有的平台对应的线程代码用 C++ 封装,对外提供统一的接口),C++ 多线程的本质是在Linux系统中 C++ 多线程操作对 pthread 库的封装。

问题:为什么 C++ 性特性支持要以年为单位?

答:从技术角度,他要把所有的平台对应的功能全部封装一遍。

问题:为什么所有语言都追求跨平台性?

答:Windows 和 Linux 背后的用户的百万级别的,如果 C++ 只支持其中的一方,就会导致 C++ 失去了其中一个平台的用户,总之支持跨平台性就是为了让更多用户使用。


未完待续!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

网站建设收费宿迁网站建设

第一章:Open-AutoGLM自定义确认函数开发概述在构建基于大语言模型的自动化系统时,Open-AutoGLM 提供了灵活的接口支持开发者实现自定义逻辑,

2026/06/30 12:06:29

建设局网站甘肃网站建设

LiDAR-Camera校准终极指南:从入门到精通完整解析【免费下载链接】lidar_camera_calibrationROS package to find a rigid-body

2026/06/30 11:10:54

高端 网站建设p2p网站建设

蚂蚁密算案例该数据要素案例由蚂蚁密算投递并参与金猿组委会×数据猿×上海大数据联盟共同推出的《2025中国大数据产业年度数据要素价值释放案例》榜单/奖项评选。大数据产业创新服务媒体——聚焦数据 · 改变

2026/06/30 13:14:35

梧州网站建设网站建设报告

从零开始玩转ESP32音频分类:给嵌入式新手的实战指南你有没有想过,让一块不到10块钱的ESP32板子“听懂”世界?比如它能分辨出玻璃碎了、有人在拍手、门被猛

2026/06/30 14:13:39

网站建设项目网站的建设

GitHub Projects 项目管理:高效追踪 PyTorch 功能开发进度在深度学习项目日益复杂的今天,一个常见的困境是:代码跑通了,但团

2026/06/30 13:25:35

濮阳网站建设建设网站建设

当你因误删关键道具而陷入重玩数十小时的绝望,当角色属性加点失误让你在Boss战前寸步难行,《艾尔登法环》的存档系统似乎成了无法逾越的障碍。但一款名为ER-Save-Edit

2026/06/30 12:52:03

服装网站建设建设工程网站

DDU显卡驱动清理神器:3步彻底解决驱动残留问题【免费下载链接】display-drivers-uninstallerDisplay Driver Uninstaller (DDU) a

2026/06/30 11:09:24

长春网站建设湖北网站建设

OASIS终极指南:构建百万级智能体社交模拟平台的5大核心功能【免费下载链接】oasis🏝️ OASIS: Open Agent Social Interaction S

2026/06/30 10:41:51

网站建设空间山西网站建设

一、关键词社区居民友爱互助平台,社区邻里互助平台,居民友爱帮扶平台二、作品包含源码+数据库+全套环境和工具资源+本地部署教程三、项目技术前端技术&#

2026/06/30 12:47:33