线程等待

pthread_join()

pthread_join  是 Linux 系统中用于线程同步的重要函数,主要作用是等待指定线程结束并回收其资源。

基本功能

- 阻塞当前调用线程,直到目标线程执行结束。
- 回收目标线程的资源,避免产生“僵尸线程”。
- 可选地获取目标线程的返回值。

函数原型

#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);

-  thread :需要等待的目标线程 ID(由  pthread_create  返回)。
-  retval :用于存储目标线程的返回值(若不需要,可设为  NULL )。
- 返回值:成功返回 0,失败返回非 0 错误码。


使用示例

#include <pthread.h>
#include <stdio.h>void *thread_func(void *arg) {printf("子线程执行\n");return (void *)100; // 子线程返回值
}int main() {pthread_t tid;pthread_create(&tid, NULL, thread_func, NULL);void *ret;pthread_join(tid, &ret); // 等待子线程结束,获取返回值printf("子线程返回值:%d\n", (int)ret);return 0;
}

注意事项

- 每个线程只能被  pthread_join  一次,多次调用会出错。
- 若不调用  pthread_join  且未设置线程分离( pthread_detach ),线程结束后资源不会被回收,会成为僵尸线程。
- 若目标线程已结束, pthread_join  会立即返回并回收资源。

线程退出

方式1

return 

方式2

pthread_exit()pthread_exit  是 Linux 中用于线程退出的函数,定义在  <pthread.h>  头文件中,用于终止当前线程的执行并返回退出状态。

基本用法

- 函数原型: void pthread_exit(void *retval); 
- 参数  retval :指向线程退出状态的指针,其他线程可通过  pthread_join  获取该值。
- 作用:终止调用线程,释放线程资源(但不会自动释放线程创建时分配的堆内存等,需手动管理)。


关键特点

- 仅终止当前线程:与  exit  不同, pthread_exit  只结束调用它的线程,不影响进程中其他线程的执行。
- 退出状态传递:通过  retval  传递的状态需为全局变量或动态分配的内存(避免栈内存被释放),否则其他线程可能获取到无效值。
- 与  return  的区别:在线程函数中使用  return  与  pthread_exit  效果类似,但  pthread_exit  更灵活(可在函数中任意位置调用)。

示例

#include <pthread.h>
#include <stdio.h>void *thread_func(void *arg) {int *result = malloc(sizeof(int));*result = 100;pthread_exit(result); // 线程退出并返回结果
}int main() {pthread_t tid;void *ret;pthread_create(&tid, NULL, thread_func, NULL);pthread_join(tid, &ret); // 获取线程退出状态printf("线程返回值:%d\n", *(int*)ret);free(ret); // 释放动态分配的内存return 0;
}

上述示例中,线程通过  pthread_exit  返回动态分配的结果,主线程通过  pthread_join  获取并释放内存。

方式3

pthread_cancel()(线程的取消)

pthread_cancel  是 Linux 中用于取消线程执行的函数,属于 POSIX 线程库(pthread)的一部分,其作用是请求终止指定的线程。

基本语法

#include <pthread.h>
int pthread_cancel(pthread_t thread);

- 参数  thread :目标线程的 ID(由  pthread_create  返回)。
- 返回值:成功返回 0,失败返回非 0 错误码(如  ESRCH  表示线程不存在)。

核心特点

1. 请求而非强制终止
pthread_cancel  只是发送一个“取消请求”,并非立即终止线程。线程是否响应、何时响应,取决于其“取消状态”和“取消类型”。
2. 取消状态(可通过  pthread_setcancelstate  设置)
-  PTHREAD_CANCEL_ENABLE (默认):线程允许响应取消请求。
-  PTHREAD_CANCEL_DISABLE :线程忽略取消请求,直到状态改为允许。
3. 取消类型(可通过  pthread_setcanceltype  设置,仅当状态为允许时有效)
-  PTHREAD_CANCEL_DEFERRED (默认):线程在“取消点”(如  sleep 、 read  等系统调用)处响应请求。
-  PTHREAD_CANCEL_ASYNCHRONOUS :线程立即响应请求(较少使用,可能导致资源未释放)。

注意事项

- 线程被取消后,资源(如锁、内存)需通过“线程清理函数”( pthread_cleanup_push / pthread_cleanup_pop )释放,避免泄漏。
- 并非所有函数都是取消点,可通过  pthread_testcancel  主动检查取消请求(手动创建取消点)。


示例:通过  pthread_cancel  取消一个延迟响应的线程,需确保线程在取消点处被终止。

注意

线程间的通信不仅仅只可以交流传输字符串或整数

这段代码展示了如何在多线程中通过指针传递自定义对象( Request  和  Response ),实现线程间的数据交互。主要功能是创建一个子线程,计算从  start_  到  end_  的整数和,并通过  Response  对象返回结果。

代码解析

1. 自定义类

-  Request :封装线程的输入参数(计算范围  start_ / end_ 、线程名称  threadname_ )。

-  Response :封装线程的输出结果(计算总和  result_ 、状态码  exitcode_ )。

2. 线程函数  sumCount 

- 接收  Request*  类型的参数,解析输入范围并循环计算总和。

- 每次循环打印当前进度(线程名+当前计算的数字),并通过  usleep(100000)  暂停0.1秒(方便观察过程)。

- 计算完成后,创建  Response  对象存储结果,释放  Request  资源,返回  Response* 。

3. 主线程  main 

- 创建  Request  对象并传入子线程,通过  pthread_create  启动线程。

- 调用  pthread_join  等待子线程结束,获取返回的  Response*  并打印结果,最后释放资源。

 class Request{public:Request(int start, int end, const string &threadname): start_(start), end_(end), threadname_(threadname){}public:int start_;int end_;string threadname_;};class Response{public:Response(int result, int exitcode):result_(result),exitcode_(exitcode){}public:int result_;   // 计算结果int exitcode_; // 计算结果是否可靠};void *sumCount(void *args) // 线程的参数和返回值,不仅仅可以用来进行传递一般参数,也可以传递对象!!{Request *rq = static_cast<Request*>(args); //  Request *rq = (Request*)argsResponse *rsp = new Response(0,0);for(int i = rq->start_; i <= rq->end_; i++){cout << rq->threadname_ << " is runing, caling..., " << i << endl;rsp->result_ += i;usleep(100000);}delete rq;return rsp;}int main(){pthread_t tid;Request *rq = new Request(1, 100, "thread 1");pthread_create(&tid, nullptr, sumCount, rq);void *ret;pthread_join(tid, &ret);Response *rsp = static_cast<Response *>(ret);cout << "rsp->result: " << rsp->result_ << ", exitcode: " << rsp->exitcode_ << endl;delete rsp;return 0;}

线程及轻量化进程底层实现逻辑运用的是clone

clone 

 在 Linux 中, clone  是一个系统调用,主要用于创建新的进程(或线程),与  fork  相比,它提供了更精细的控制能力,可以指定新进程与父进程共享哪些资源。
 
clone  的核心特点

- 灵活的资源共享:通过参数可以指定新进程是否共享父进程的内存空间、文件描述符表、信号处理等资源。例如,创建线程时通常会共享内存空间,而创建独立进程时则不共享。
- 与  fork  的关系: fork  可以看作是  clone  的一种特殊情况( clone  省略部分参数时的简化版), fork  会复制父进程的几乎所有资源,而  clone  可按需共享。

主要用途

- 创建线程(如 POSIX 线程 pthread 底层可能使用  clone ,共享内存空间)。
- 创建具有特定资源共享策略的进程,满足特殊场景需求(如轻量级进程 LWP)。

简单来说, clone  是 Linux 中一个更底层、更灵活的进程/线程创建工具,通过控制资源共享粒度,适应不同的并发场景。

由于clone相对于用户而言使用过于复杂,因此 Clone被包装成库供用户使用,开发者将要调用的函数指针和栈区暴露出来给用户使用,由于操作系统要对线程进行管理,而线程共用一个动态库,因此副线程它主要存储在共享区,而主线程及进程它是存放在内核的主线程栈中

TCB

在 Linux 中,TCB(Thread Control Block,线程控制块) 是内核中用于管理线程状态的核心数据结构,类似于进程的 PCB(Process Control Block),但专门用于线程。

TCB 的主要作用

- 存储线程的基本信息,如线程 ID(TID)、状态(运行、就绪、阻塞等)。
- 记录线程的上下文(寄存器值、程序计数器等),用于线程切换时保存和恢复状态。
- 关联线程所属的进程(进程 PCB),以及线程组信息。
- 管理线程的栈指针、信号掩码、调度优先级等私有资源。

与 clone 的关系

当使用  clone  创建线程时(如指定  CLONE_THREAD 、 CLONE_VM  等标志),内核会为新线程创建一个 TCB,同时共享进程的部分资源(如内存空间)。TCB 是内核识别和调度线程的关键,确保每个线程能独立被调度,同时与同进程其他线程协作。

简单说,TCB 就是线程在内核中的“身份证”和“状态档案”,支撑线程的独立运行和管理。

TID

在 Linux 中,TID(Thread ID,线程 ID) 是用于唯一标识线程的编号,类似于进程的 PID(Process ID),但专门针对线程。

TID 的特点

- 唯一性:系统中每个线程都有一个唯一的 TID,即使是同一进程内的不同线程,TID 也互不相同。
- 与 PID 的关系:在 Linux 中,线程本质上是轻量级进程(LWP),因此 TID 在内核中与 PID 共享同一编号空间(即 TID 也是一个“进程 ID”,但属于线程级别的标识)。
- 线程组关联:同一进程的所有线程属于同一个线程组,线程组的领头线程(通常是进程创建的第一个线程)的 TID 等于进程的 PID。

作用

- 内核通过 TID 识别和调度不同的线程。
- 用户态可通过  gettid()  系统调用获取当前线程的 TID,用于线程管理、调试等场景(如  ps -T  命令可查看进程内的线程 TID)。


例如,一个进程包含 3 个线程,它们会有各自不同的 TID,但共享同一个进程 PID(等于领头线程的 TID)。

分散线程

Linux 中的分离线程(Detached Thread) 是一种特殊状态的线程,核心特点是:

- 线程结束后会自动释放资源(如栈、寄存器等),无需其他线程调用  pthread_join()  等待回收。
- 无法通过  pthread_join()  获取其退出状态。


主要用途

避免线程资源泄漏,适用于不需要等待其完成、也无需获取结果的场景(如后台日志打印、异步任务等)。

设置方式

1. 创建时指定:通过  pthread_attr_t  设置属性为  PTHREAD_CREATE_DETACHED 。
2. 创建后设置:调用  pthread_detach(pthread_t thread)  函数将线程转为分离状态。

分离线程的核心是自动回收资源,简化线程管理,避免手动回收的繁琐。

pthread_detach  是 POSIX 线程库中的一个函数,用于将指定线程设置为分离状态(detached)。

核心作用

让目标线程在结束时自动释放所有资源(如栈空间、线程描述符等),无需其他线程通过  pthread_join  来等待或回收。

函数原型

#include <pthread.h>
int pthread_detach(pthread_t thread);

- 参数  thread :要设置为分离状态的线程 ID(由  pthread_create  返回)。
- 返回值:成功返回 0,失败返回非 0 错误码(如线程不存在)。

使用场景

适用于不需要获取线程退出状态、也无需等待其完成的场景(例如后台服务线程、日志打印线程),避免资源泄漏。

注意点

- 线程一旦被分离,就无法再通过  pthread_join  获取其状态,调用会失败。
- 可在线程创建后立即调用(通常由主线程或线程自身调用),也可在创建时通过属性直接指定为分离状态(更高效)。


简单说, pthread_detach  就是“告诉系统:这个线程结束后自己收拾干净,不用别人管了”。  

线程私有化关键字__thread 

__thread  是 GCC 编译器(GNU C 扩展)提供的关键字,用于声明线程局部变量(Thread-Local Variables),实现线程空间私有化。它的作用是让变量在每个线程中拥有独立的副本,线程对变量的操作仅影响自身副本,不干扰其他线程。

主要特点

- 适用场景:主要用于 C/C++ 代码,需配合 GCC 编译器(或支持该扩展的编译器,如 Clang)。
- 生命周期:变量的生命周期与线程一致,线程创建时初始化,线程结束时自动销毁。
- 初始化限制:只能用常量初始化(不能用运行时动态计算的值)。

示例代码

#include <stdio.h>
#include <pthread.h>
// 声明线程局部变量,每个线程有独立副本
__thread int var = 0;void* thread_func(void* arg) {int id = *(int*)arg;var = id;  // 每个线程修改自己的副本printf("线程 %d 中的 var 值:%d\n", id, var);return NULL;
}int main() {pthread_t tid1, tid2;int id1 = 1, id2 = 2;pthread_create(&tid1, NULL, thread_func, &id1);pthread_create(&tid2, NULL, thread_func, &id2);pthread_join(tid1, NULL);pthread_join(tid2, NULL);return 0;
}


 输出会显示两个线程的  var  值分别为 1 和 2,互不干扰。

与  thread_local  的关系

C11 标准引入了  thread_local  关键字,作为线程局部变量的标准语法,功能与  __thread  类似。 __thread  是 GCC 的非标准扩展,而  thread_local  是跨编译器的标准实现(需编译器支持 C11 或 C++11 及以上标准)。在支持标准的情况下,更推荐使用  thread_local  以保证可移植性。

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

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

相关文章

RAG优化秘籍:基于Tablestore的知识库答疑系统架构设计

目录一、技术架构设计二、双流程图解析横向架构对比纵向核心流程三、企业级代码实现Python检索核心TypeScript前端接入YAML部署配置四、性能对比验证五、生产级部署方案六、技术前瞻分析附录&#xff1a;完整技术图谱一、技术架构设计 原创架构图 #mermaid-svg-3Ktoc4oH4xlbD6…

i.mx8 RTC问题

项目场景&#xff1a;需要增加外置RTC&#xff0c;保证时间的精准。问题描述&#xff1a;基本情况&#xff0c;外置i2c接口的RTC&#xff0c;注册、读写都正常&#xff0c;但是偶发性重启后&#xff0c;系统时间是2022&#xff0c;rtc时间是1970&#xff0c;都像是恢复了默认时…

数据集相关类代码回顾理解 | utils.make_grid\list comprehension\np.transpose

目录 utils.make_grid list comprehension np.transpose utils.make_grid x_gridutils.make_grid(x_grid, nrow4, padding2) make_grid 函数来自torchvision的utils模块&#xff0c;用于图像数据可视化&#xff0c;将一批图像排列成一个网格。 x_grid&#xff1a;四维图像…

C#中Static关键字解析

本文仅作为参考大佬们文章的总结。 Static关键字是C#语言中一个基础而强大的特性&#xff0c;它能够改变类成员的行为方式和生命周期。本文系统性总结static关键字的各类用法、核心特性、适用场景以及需要注意的问题&#xff0c;以帮助掌握这一重要概念。 一、Static关键字概…

通用综合文字识别联动 MES 系统:OCR 是数据流通的核心

制造业的 MES 系统需实时整合生产数据以调控流程&#xff0c;但车间的工单、物料标签、质检报告等多为纸质或图片形式&#xff0c;传统人工录入不仅滞后&#xff0c;还易出错&#xff0c;导致 MES 系统数据断层。通用综合文字识别借助 OCR 技术&#xff0c;成为连接这些信息与 …

【Linux 学习指南】网络编程基础:从 IP、端口到 Socket 与 TCP/UDP 协议详解

文章目录&#x1f4dd;理解源IP地址和目的IP地址&#x1f320; 认识端口号&#x1f309;端口号范围划分&#x1f309;理解"端口号"和"进程ID"&#x1f309;理解源端口号和目的端口号&#x1f309;理解socket&#x1f320;传输层的典型代表&#x1f309;认识…

React+Next.js+Tailwind CSS 电商 SEO 优化

一、项目背景与技术选型​1. 原始痛点​项目最初基于纯 React 开发&#xff08;SPA 架构&#xff09;&#xff0c;存在三个致命问题&#xff1a;​搜索引擎爬虫无法有效抓取动态渲染的商品详情、分类页内容&#xff1b;​单页面应用 难以实现页面级的 meta 定制&#xff0c;关键…

Process Lasso:提升电脑性能的得力助手

在日常使用电脑的过程中&#xff0c;我们常常会遇到这样的问题&#xff1a;电脑运行缓慢、程序响应迟缓、多任务处理时卡顿不断。这些问题不仅影响工作效率&#xff0c;还让人感到非常烦躁。其实&#xff0c;这些问题很多时候是因为电脑的进程管理不够优化。而Process Lasso正是…

AI驱动的大前端内容创作与个性化推送:资讯类应用实战指南

在信息爆炸的时代&#xff0c;资讯类应用面临两大核心挑战&#xff1a;一是如何高效生产海量优质内容&#xff0c;二是如何让用户从海量信息中快速获取感兴趣的内容。AI技术的介入正在重构资讯类应用的开发模式&#xff0c;从内容生产到用户触达形成全链路智能化。本文将从开发…

2025/7/16——java学习总结

Java IO 流全体系总结&#xff1a;从基础到实战的完整突破&#xff08;重写&#xff09;一、基础核心&#xff1a;字节流与字符流的底层逻辑&#xff08;一&#xff09;字节流&#xff1a;二进制数据的读写基础操作字节输入流&#xff1a;掌握 FileInputStream 单字节读取细节&…

书籍自然数数组的排序(8)0715

题目给定一个长度为N的整型数组arr&#xff0c;其中有N个互不相等的自然数1~N&#xff0c;请实现arr的排序&#xff0c;但是不要把下标0~N-1位置上的数通过直接赋值的方式替换成1~N。解答 arr在调整之后应该事下标从0到N-1的位置上依次放着1~N&#xff0c;即arr[index] index …

【08】MFC入门到精通——MFC模态对话框 和 非模态对话框 解析 及 实例演示

文章目录八、模态对话框 和 非模态对话框 创建及显示8.1 对话框是怎样弹出的8.2 模态对话框的创建及显示8.3 非模态对话框的创建及显示8.4 完整代码下载八、模态对话框 和 非模态对话框 创建及显示 Windows对话框分为两类&#xff1a;模态对话框 和 非模态对话框。 模态对话框…

github上传大文件(多种解决方案)

之前一直用vscode的上传项目方法&#xff0c;这个方便之处在于不用打开git终端输入各种命令&#xff0c;不过麻烦的是我一直无法拉取github上的远程仓库提交&#xff0c;每次只能更新已有的仓库并且上传的文件还不能太大&#xff0c;应该是不能超过100MB&#xff0c;而且直接在…

生活污水深度除磷的方法

生活污水中磷含量过多的危害大家都知道总磷是水质检测的重要指标之一&#xff0c;在污水处理中生活污水往往都会出现总磷超标的现象。生活污水磷超标的危害是多方面的主要包括水体富营养化、危害水生生物、影响人类健康&#xff0c;以及可能引发蓝藻水华等问题。除磷方法污水的…

Flutter瀑布流布局深度实践:打造高性能动态图片墙

本文将深入探讨如何在Flutter中实现高性能瀑布流布局&#xff0c;解决动态高度内容展示的核心难题&#xff0c;并带来卓越的用户体验。引言&#xff1a;瀑布流布局的魅力 瀑布流布局(Pinterest-style layout)已成为现代应用展示图片和内容的黄金标准。它通过错落有致的排列方式…

OpenCV 伽马校正函数gammaCorrection()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 该函数用于对输入图像应用伽马校正&#xff08;Gamma Correction&#xff09;&#xff0c;这是一种非线性的图像处理技术&#xff0c;主要用于调整…

Linux-局域网构建+VLAN 划分 + 端口 MAC-IP 绑定 + 静态 DHCP

文章目录1. 适用于家庭、工作室或小型企业的局域网构建2. VLAN划分3. VLAN 划分 端口 MAC-IP 绑定 静态 DHCP跳转→网络管理基础复习 1. 适用于家庭、工作室或小型企业的局域网构建 ✅ 一、硬件连线&#xff08;一次到位&#xff09; 光纤入户 → 光猫/宽带调制解调器光猫…

渗透测试路线

渗透测试学习路线报告&#xff08;从入门到高级&#xff09; 引言&#xff1a;渗透测试概述与学习路线设计 渗透测试作为网络安全体系中的核心实践环节&#xff0c;通过模拟真实攻击者的技术手段与攻击路径&#xff0c;主动识别信息系统中的安全漏洞、评估防护机制有效性&#…

Node.js 中http 和 http/2 是两个不同模块对比

1. 核心模块对比 特性http 模块 (HTTP/1.1)http2 模块 (HTTP/2)协议版本HTTP/1.1&#xff08;文本协议&#xff09;HTTP/2&#xff08;二进制协议&#xff09;多路复用不支持&#xff08;需多个 TCP 连接&#xff09;支持&#xff08;单连接多流&#xff09;头部压缩无HPACK 压…

3DGS之COLMAP

COLMAP 在 3DGS 中起到了数据预处理和三维重建的关键作用&#xff0c;其处理流程包括特征提取与匹配、稀疏重建、稠密重建和输出文件生成。结合 3DGS 的高斯分布建模和优化算法&#xff0c;COLMAP 提供了场景的几何和相机信息&#xff0c;为实时渲染和三维重建奠定了基础。一、…