POSIX 线程取消与资源清理完全指南

news2025/3/31 9:23:24

POSIX 线程取消与资源清理完全指南

引言:为什么需要线程取消机制?

在多线程编程中,优雅地终止线程并确保资源释放是开发者面临的重要挑战。直接终止线程可能导致内存泄漏、文件未关闭等问题。POSIX 线程库提供了一套完整的线程取消和清理机制,本文将深入解析这些关键API的使用方法。


一、线程终止的三种方式

  1. 隐式终止:线程函数执行return
  2. 显式终止:调用pthread_exit()
  3. 强制终止:通过pthread_cancel()请求取消

⚠️ 注意:直接使用return退出线程不会触发清理函数!


二、线程取消请求机制

1. pthread_cancel()

int pthread_cancel(pthread_t thread);
  • 功能:向目标线程发送取消请求
  • 特性
    • 非阻塞操作
    • 实际终止时机取决于线程的取消状态和类型
    • 常见取消点:sleep(), read(), pthread_join()等阻塞调用

2. pthread_testcancel()

void pthread_testcancel(void);
  • 作用:显式创建取消点
  • 应用场景
    • 长时间运行的循环中插入检查点
    • 非阻塞代码路径中主动响应取消请求
// 示例:在计算密集型循环中添加取消检查
while(1) {
    pthread_testcancel();
    // 复杂计算...
}

三、取消状态与类型控制

1. 状态控制 pthread_setcancelstate()

int pthread_setcancelstate(int state, int *oldstate);
状态值说明
PTHREAD_CANCEL_ENABLE允许取消(默认)
PTHREAD_CANCEL_DISABLE禁止取消请求

2. 类型控制 pthread_setcanceltype()

int pthread_setcanceltype(int type, int *oldtype);
类型值说明
PTHREAD_CANCEL_DEFERRED延迟取消(默认)
PTHREAD_CANCEL_ASYNCHRONOUS异步取消(立即终止)

🔑 最佳实践:异步取消应谨慎使用,可能导致资源未释放!


四、线程清理函数

1. 注册清理函数

void pthread_cleanup_push(void (*routine)(void*), void* arg);

2. 注销清理函数

void pthread_cleanup_pop(int execute);

3. 关键特性

  • 后进先出(LIFO)执行顺序
  • 触发条件
    • 调用pthread_exit()
    • 线程被取消
    • 执行pthread_cleanup_pop(1)

4. 典型应用模式

void* thread_func(void* arg) {
    FILE *fp = fopen("data.txt", "r");
    pthread_cleanup_push(cleanup_file, fp);
    
    while(1) {
        // 文件操作...
        pthread_testcancel();
    }
    
    pthread_cleanup_pop(1); // 正常退出时主动清理
    return NULL;
}

void cleanup_file(void* arg) {
    FILE *fp = (FILE*)arg;
    if(fp) {
        fclose(fp);
        printf("File closed\n");
    }
}

五、完整示例:安全的线程取消

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

typedef struct {
    int *buffer;
    FILE *logfile;
} ThreadResource;

void cleanup_handler(void *arg) {
    ThreadResource *res = (ThreadResource *)arg;
    printf("Cleaning up resources...\n");
    
    if (res->buffer) {
        free(res->buffer);
        res->buffer = NULL;
    }
    
    if (res->logfile) {
        fclose(res->logfile);
        res->logfile = NULL;
    }
}

void* worker_thread(void *arg) {
    ThreadResource resources = {0};
    
    // 申请资源
    resources.buffer = malloc(1024);
    resources.logfile = fopen("thread.log", "w");
    
    // 注册清理函数
    pthread_cleanup_push(cleanup_handler, &resources);
    
    // 设置取消类型为延迟取消
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    
    while(1) {
        // 模拟工作
        fprintf(resources.logfile, "Working...\n");
        sleep(1);
        
        // 显式取消点
        pthread_testcancel();
    }
    
    // 正常退出时执行清理
    pthread_cleanup_pop(1);
    return NULL;
}

int main() {
    pthread_t tid;
    pthread_create(&tid, NULL, worker_thread, NULL);

    sleep(3);
    printf("Requesting thread cancellation...\n");
    pthread_cancel(tid);

    pthread_join(tid, NULL);
    printf("Thread terminated safely\n");
    return 0;
}

六、最佳实践与注意事项

  1. 资源管理三原则

    • 每个资源申请操作后立即注册清理函数
    • 使用结构体组织相关资源
    • 清理函数中实现幂等操作
  2. 取消点设计

    • 在循环体内定期调用pthread_testcancel()
    • 避免在临界区设置取消点
    • 对关键操作临时禁用取消
  3. 错误处理

    if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0) {
        // 错误处理...
    }
    
  4. 调试技巧

    • 使用GDB观察清理栈:info threads + thread apply all bt
    • 记录清理函数执行日志
    • 使用Valgrind检测资源泄漏

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

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

相关文章

FPGA学习篇——Verilog学习之寄存器的实现

1 寄存器理论 这里在常见的寄存器种加了一个复位信号sys_rst_n。&#xff08;_n后缀表示复位信号低电平有效&#xff0c;无这个后缀的则表示高电平有效&#xff09; 这里规定在时钟的上升沿有效&#xff0c;只有当时钟的上升沿来临时&#xff0c;输出out 才会改变&#xff0c;…

【VUE】ant design vue实现表格table上下拖拽排序

适合版本&#xff1a;ant design vue 1.7.8 实现效果&#xff1a; 代码&#xff1a; <template><div class"table-container"><a-table:columns"columns":dataSource"tableData":rowKey"record > record.id":row…

Vue实现动态数据透视表(交叉表)

需求:需要根据前端选择的横维度、竖维度、值去生成一个动态的表格&#xff0c;然后把交叉的值放入到对应的横维度和竖维度之下&#xff0c;其实就是excel里面的数据透视表功能&#xff0c;查询交叉语句为sql语句。 实现页面&#xff1a; 选择一下横维度、竖维度、值之后点击查…

推荐《人工智能算法》卷1、卷2和卷3 合集3本书(附pdf电子书下载)

今天&#xff0c;咱们就一同深入探讨人工智能算法的卷1、卷2和卷3&#xff0c;看看它们各自蕴含着怎样的奥秘&#xff0c;并且附上各自的pdf电子版免费下载地址。 《人工智能算法&#xff08;卷1&#xff09;&#xff1a;基础算法》 下载地址&#xff1a;https://www.panziye…

元宇宙浪潮下,数字孪生如何“乘风破浪”?

在当今科技飞速发展的时代&#xff0c;元宇宙的概念如同一颗璀璨的新星&#xff0c;吸引了全球的目光。元宇宙被描绘为一个平行于现实世界、又与现实世界相互影响且始终在线的虚拟空间&#xff0c;它整合了多种前沿技术&#xff0c;为人们带来沉浸式的交互体验。而数字孪生&…

数据分析 之 怎么看懂图 一

韦恩图怎么看 ①颜色:不同颜色代表不同的集合 ②)颜色重叠部分:表示相交集合共有的元素 ③颜色不重叠的部分:表示改集合独有的元素 ④数字:表示集合独有或共有的元素数量 ⑤百分比:表示该区域元素数占整体的比例 PCA图怎么看 ① 第一主成分坐标轴及主成分贡献率主成分贡献…

手写数据库MYDB(一):项目启动效果展示和环境配置问题说明

1.项目概况 这个项目实际上就是一个轮子项目&#xff0c;现在我看到的这个市面上面比较火的就是这个首先RPC&#xff0c;好多的机构都在搞这个&#xff0c;还有这个消息队列之类的&#xff0c;但是这个是基于MYSQL的&#xff0c;我们知道这个MYSQL在八股盛宴里面是重点考察对象…

深入理解椭圆曲线密码学(ECC)与区块链加密

椭圆曲线密码学&#xff08;ECC&#xff09;在现代加密技术中扮演着至关重要的角色&#xff0c;广泛应用于区块链、数字货币、数字签名等领域。由于其在提供高安全性和高效率上的优势&#xff0c;椭圆曲线密码学成为了数字加密的核心技术之一。本文将详细介绍椭圆曲线的基本原理…

Intellij IDEA2023 创建java web项目

Intellij IDEA2023 创建java web项目 零基础搭建web项目1、创建java项目2、创建web项目3、创建测试页面4、配置tomcat5、遇到的问题 零基础搭建web项目 小白一枚&#xff0c;零基础学习基于springMVC的web项目开发&#xff0c;记录开发过程以及中间遇到的问题。已经安装了Inte…

Scrapy结合Selenium实现滚动翻页数据采集

引言 在当今的互联网数据采集领域&#xff0c;许多网站采用动态加载技术&#xff08;如AJAX、无限滚动&#xff09;来优化用户体验。传统的基于Requests或Scrapy的爬虫难以直接获取动态渲染的数据&#xff0c;而Selenium可以模拟浏览器行为&#xff0c;实现滚动翻页和动态内容…

sqlmap 源码阅读与流程分析

0x01 前言 还是代码功底太差&#xff0c;所以想尝试阅读 sqlmap 源码一下&#xff0c;并且自己用 golang 重构&#xff0c;到后面会进行 ysoserial 的改写&#xff1b;以及 xray 的重构&#xff0c;当然那个应该会很多参考 cel-go 项目 0x02 环境准备 sqlmap 的项目地址&…

DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例6,TableView16_06 分页表格拖拽排序

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

基于物联网的新房甲醛浓度监测系统的设计(论文+源码)

2.1总体方案设计 本次基于物联网的新房甲醛浓度监测系统的设计其系统总体架构如图2.1所示&#xff0c;整个系统在硬件架构上采用了STM32f103作为主控制器&#xff0c;在传感器部分采用了MQ135实现甲醛浓度的检测&#xff0c;并且通过ESP8266 WiFi模块将当前检测的数据传输到手…

【AI学习】人工神经网络

1,人工神经网络(Artificial Neural Networks,ANNs,连接模型,Connection Model) 模仿动物神经网络行为特征(突触联接的结构),进行分布式并行信息处理的算法数学模型。依靠系统的复杂程度,通过调整内部大量节点之间相互连接的关系,从而达到处理信息的目的。 2,前馈神…

linux--网络协议初识

linux–网络协议初识 事实: 通信的主机之间距离变长了---->引发出新的通信问题? 如何使用数据问题(应用层)可靠性问题(传输层)主机定位问题(网络层)数据报局域网转发问题(数据链路层) 人提出网络协议解决方案—方案有好有坏–为了方便扩展,替换或维护–故将网络协议设置…

uniapp用户登录及获取用户信息(头像昵称)

低版本情况 微信开发者工具的基础库版本要调到2.27版本以下&#xff0c;能够直接申请用户权限获取用户信息&#xff0c;但是会仅限于开发者调试&#xff0c;在真机测试或已上传的小程序在手机上就不能获取以上的原因是微信小程序wx.getUserProfile 和wx.getUserInfo 这两个获取…

Linux下EC11旋转编码器驱动调试

文章目录 1、前言2、使用gpio-keys驱动2.1、dts配置2.2、识别原理2.3、应用层驱动实现2.4、编译测试 3、使用rotary-encoder驱动3.1、dts配置3.2、app测试程序编写3.3、编译测试 4、总结 1、前言 本来是没有这篇文章的。最近在rk3576下调试ec11旋转编码器时&#xff0c;一直没…

RCE——回调后门

目录 rce简述 rce漏洞 rce漏洞产生分类 rce漏洞级别 创造tips的秘籍——回调后门 call_user_func 解析 如何执行后门 call_user_func_array array_filter、array_map 解析 如何执行后门 php5.4.8中的assert——二参数的回调函数 uasort uksort array_reduce() …

Unity Shader 学习17:合批渲染

一、基础概念 合批主要是针对这三个概念进行优化减少&#xff1a; ① SetPass Call&#xff1a;一次渲染状态切换&#xff0c;也就是每次切换 材质/Pass 时&#xff0c;就会触发一次SetPass Call ② Draw Call&#xff1a;cpu 调用一次 gpu 绘制函数 ③ Batch&#xff1a;表示…

带你从入门到精通——自然语言处理(十. BERT)

建议先阅读我之前的博客&#xff0c;掌握一定的自然语言处理前置知识后再阅读本文&#xff0c;链接如下&#xff1a; 带你从入门到精通——自然语言处理&#xff08;一. 文本的基本预处理方法和张量表示&#xff09;-CSDN博客 带你从入门到精通——自然语言处理&#xff08;二…