C/C++|关于“子线程在堆中创建了资源但在资源未释放的情况下异常退出或挂掉”如何避免?

文章目录

  • 主线程监控子线程状态并负责清理资源
  • 使用智能指针(RAII模式)
  • 线程清理处理函数(pthread_cleanup_push、pthread_cleanup_pop)
  • 使用资源管理器或资源吃集中管理资源
  • 通过信号或全局变量监控线程状态
  • 使主线程负责分配和释放资源

在 C/C++ 中处理子线程分配的动态资源因线程异常退出而无法释放的问题,可以采用以下方法。我们将逐条分析并给出示例代码。

主线程监控子线程状态并负责清理资源

使用智能指针管理堆中的资源。

#include <pthread.h>
#include <unistd.h>#include <iostream>void* threadFunc(void* arg) {int* data = new int(42);*(int**)arg = data;  // 将资源的地址传递给主线程sleep(1);// 模拟子线程崩溃pthread_exit(NULL);delete data;  // 正常情况下应该释放资源,但是这里不会执行return NULL;
}int main() {pthread_t thread;int* sharedData = NULL;pthread_create(&thread, NULL, threadFunc, &sharedData);// 等待子线程完成void* status;pthread_join(thread, &status);// 如果子线程未释放资源,主线程负责清理if (sharedData != NULL) {std::cout << "Cleaning up memory in main thread: " << *sharedData<< std::endl;delete sharedData;}return 0;
}

使用智能指针(RAII模式)

这里我们一般是在C++中,当然,在C语言里也可以做类似的封装。

智能指针(如 std::unique_ptr 或 std::shared_ptr)可以自动管理资源生命周期,即使子线程崩溃,也会在对象销毁时释放资源。这种方法利用了 RAII 模式,减少手动清理的复杂性。

#include <pthread.h>
#include <unistd.h>#include <iostream>
#include <memory>void* threadFunc(void* arg) {std::unique_ptr<int> data(new int(42));  // 使用智能指针分配资源std::cout << "Data in thread: " << *data << std::endl;sleep(1);// 模拟子线程崩溃pthread_exit(NULL);return nullptr;
}int main() {pthread_t thread;pthread_create(&thread, NULL, threadFunc, nullptr);pthread_join(thread, nullptr);// 完全不需要手动释放资源std::cout << "Resource cleanup is handled by unique_ptr." << std::endl;return 0;
}

线程清理处理函数(pthread_cleanup_push、pthread_cleanup_pop)

在子线程中注册清理函数,以确保无论线程如何退出(正常或异常),清理函数都会被调用并释放资源。

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>void cleanup(void* arg) {free(arg);printf("Resource freed in cleanup handler\n");
}void* threadFunc(void* arg) {int* resource = (int*)arg;pthread_cleanup_push(cleanup, resource);  // 注册清理函数// 使用资源*resource = 10;printf("Resource used in thread: %d\n", *resource);// 模拟异常退出pthread_exit(NULL);pthread_cleanup_pop(0);  // 0 表示不自动调用清理函数return NULL;
}int main() {pthread_t thread;int* resource = (int*)malloc(sizeof(int));if (resource == NULL) {perror("Failed to allocate memory");return -1;}*resource = 5;// 创建子线程if (pthread_create(&thread, NULL, threadFunc, resource) != 0) {perror("Failed to create thread");free(resource);  // 如果线程创建失败,释放资源return -1;}// 等待子线程结束pthread_join(thread, NULL);return 0;
}

使用资源管理器或资源吃集中管理资源

在该方法中,创建一个资源管理器,集中管理所有线程分配的资源。资源管理器记录每个资源的生命周期,并在必要时自动回收。

#include <iostream>
#include <pthread.h>
#include <unordered_map>
#include <mutex>class ResourceManager {
public:void allocateResource(int threadID) {std::lock_guard<std::mutex> lock(mutex_);resource_[threadID] = new int(42); // 分配资源}
private:std::unordered_map<int, int*> resource_;std::mutex mutex_;
};ResourceManager manager;void* threadFunc(void* arg) {int threadId = *reinterpret_cast<int*>(arg);manager.allocateResource(threadId);    // 请求资源管理器分配资源pthread_exit(nullptr);                 // 模拟线程异常退出return nullptr;
}int main() {pthread_t thread1, thread2;int id1 = 1, id2 = 2;pthread_create(&thread1, nullptr, threadFunc, &id1);pthread_create(&thread2, nullptr, threadFunc, &id2);pthread_join(thread1, nullptr);pthread_join(thread2, nullptr);// 主线程可以在这里清理manager.releaseResource(id1);manager.releaseResource(id2);return 0;
}

通过信号或全局变量监控线程状态

使用信号或全局变量监控线程状态是实现线程间通信的一种方法。它允许主线程检测子线程的状态(例如,是否正在运行或已结束),并在必要时采取相应措施(如主动释放资源)。为了确保线程间的同步,通常需要借助 互斥锁(std::mutex) 或 原子变量(std::atomic) 来保证数据读写的安全性。
在下面这个示例中,我们定义了一个全局原子变量 thread_running 来表示子线程的状态。主线程会定期检查该变量的状态,并在子线程异常退出时主动释放资源。

在C语言中,我们没有 std::atomic 和 智能指针这样的高级特性,但可以通过 全局变量和互斥锁 来实现类似的功能。
在下面这个示例中,主线程通过一个全局变量 thread_running 来监控子线程的状态。子线程在开始运行时将 thread_running 设置为 1,表示正在运行;当异常退出或结束时,将 thread_running 设置为 0,表示已停止。主线程定期检查 thread_running 的状态,如果检测到子线程已停止,则进行清理操作。

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int* shared_data = NULL;       // 堆区资源
int thread_running = 0;        // 线程状态标志
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  // 互斥锁保护资源void* threadFunc(void* arg) {pthread_mutex_lock(&mutex);shared_data = (int*)malloc(sizeof(int));   // 分配堆区资源if (shared_data == NULL) {perror("Failed to allocate memory");pthread_mutex_unlock(&mutex);pthread_exit(NULL);}*shared_data = 42;thread_running = 1;                         // 标记子线程正在运行pthread_mutex_unlock(&mutex);printf("Data in thread: %d\n", *shared_data);sleep(2);  // 模拟子线程运行时间// 模拟子线程异常退出,直接退出而不释放资源pthread_mutex_lock(&mutex);thread_running = 0;                         // 子线程即将退出pthread_mutex_unlock(&mutex);pthread_exit(NULL);
}int main() {pthread_t thread;// 创建子线程if (pthread_create(&thread, NULL, threadFunc, NULL) != 0) {perror("Failed to create thread");return 1;}// 主线程监控子线程状态while (1) {pthread_mutex_lock(&mutex);if (thread_running == 0 && shared_data != NULL) {// 子线程已退出,但资源未释放,主线程进行清理printf("Main thread cleaning up memory: %d\n", *shared_data);free(shared_data);shared_data = NULL;}pthread_mutex_unlock(&mutex);if (thread_running == 0) {break; // 子线程已退出,主线程退出监控循环}sleep(1); // 定期检查子线程状态}// 等待子线程退出pthread_join(thread, NULL);pthread_mutex_destroy(&mutex);return 0;
}

使主线程负责分配和释放资源

这里主要是针对C语言中,没有智能指针和RAII这样的机制,所以我们避免在子线程中直接分配资源,而是让主线程负责分配内存,然后将该资源指针传递给子线程使用。

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>void* threadFunc(void* arg) {int* shared_resource = (int*)arg;*shared_resource = 10;pthread_exit(NULL);//模拟异常退出
}int main () {pthread_t thread;int* shared_resource = (int*)malloc(sizeof(int));if (shared_resource == NULL) {perror("Failed to allocate memory");return -1;}*shared_resource = 5;if (pthread_create(&thread, NULL, threadFunc, shared_resource) != 0) {perror("Failed to create thread");free(shared_resource);return -1;}pthread_join(thread, NULL);// 主线程负责释放资源free(shared_resource);return 0;
}

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

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

相关文章

Excel中截取中文地址转换为省、市、区

使用方法/步骤 首先我们在网页打上方方格子&#xff0c;进入官网&#xff0c;下载方方格子。 解压后进行安装&#xff0c;打开OFFIE中的EXCEL&#xff0c;可以发现新新添加一个DIY工具箱&#xff0c;其中的提取地址功能可以将字符串地址解析为省、市、区 如下图所示

引入 axios,根据 api 文档生成调用接口

起步 | Axios Docs 安装 axios npm install axios 生成 api 调用接口【可选】 https://github.com/ferdikoomen/openapi-typescript-codegen 安装 npm install openapi-typescript-codegen --save-dev 然后执行生成代码 # http://localhost:8805/api/user/v3/api-docs&a…

2款使用.NET开发的数据库系统

今天大姚给大家分享2款使用.NET开发且开源的数据库系统。 Garnet Garnet是一款由微软研究院基于.NET开源的高性能、跨平台的分布式缓存存储数据库&#xff0c;该项目提供强大的性能&#xff08;吞吐量和延迟&#xff09;、可扩展性、存储、恢复、集群分片、密钥迁移和复制功能…

ARM-8 定位发布版本 pstree 程序的 main 地址

逆向时如何找到main&#xff0c;如下&#xff1a; 1.readelf -h pstree ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2s complement, little endian Versi…

13.UE5流星火雨,引导施法技能制作

2-15 流星火雨&#xff0c;引导施法技能制作、随机数_哔哩哔哩_bilibili 目录 1.为流星火雨添加按键映射 2.创建流星火雨的动画蒙太奇 3.实现播放动画蒙太奇的逻辑 ​编辑 4.定义发射一波流星火雨的发射物 5.使用动画通知释放流星火雨 1.为流星火雨添加按键映射 创建名为流…

Web大型网站的性能测试要求和工具方法

Web大型网站的性能测试要求和工具方法涉及多个层面的考量&#xff0c;旨在确保网站在高并发访问、大数据量处理、复杂交互场景下仍能保持良好的用户体验和系统稳定性。以下是针对大型网站性能测试的主要要求和相应的工具与方法&#xff1a; 性能测试要求 1. 高并发处理能力&…

贪心算法day3(最长递增序列问题)

目录 1.最长递增三元子序列 2.最长连续递增序列 1.最长递增三元子序列 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;我们只需要设置两个数进行比较就好。设a为nums[0]&#xff0c;b 为一个无穷大的数&#xff0c;只要有比a小的数字就赋值…

在CentOS7传统部署wordpress

1 环境准备 所需环境说明CentOS7.9ip地址&#xff1a;10.0.0.7&#xff0c;可以上网PHP72系列软件下面会介绍MySQL数据库暴露端口3306&#xff0c;用户wordpress&#xff0c;库wordpressnginx版本任意wordpres v6.5.2代码下载地址&#xff1a;https://cn.wordpress.org/wordpr…

文献阅读 | Nature Methods:使用 STAMP 对空间转录组进行可解释的空间感知降维

文献介绍 文献题目&#xff1a; 使用 STAMP 对空间转录组进行可解释的空间感知降维 研究团队&#xff1a; 陈金妙&#xff08;新加坡科学技术研究局&#xff09; 发表时间&#xff1a; 2024-10-15 发表期刊&#xff1a; Nature Methods 影响因子&#xff1a; 36.1&#xff0…

vs2022搭建opencv开发环境

1 下载OpenCV库 https://opencv.org/ 下载对应版本然后进行安装 将bin目录添加到系统环境变量opencv\build\x64\vc16\bin 复制该路径 打开高级设置添加环境变量 vs2022新建一个空项目 修改属性添加头文件路径和库路径 修改链接器&#xff0c;将OpenCV中lib库里的o…

GA/T1400视图库平台EasyCVR多品牌摄像机视频平台前端监控摄像头镜头的基础知识

在现代安全监控系统中&#xff0c;摄像机镜头作为捕捉图像的关键组件&#xff0c;其选择和应用直接影响到监控图像的质量和系统的整体性能。随着技术的发展&#xff0c;摄像机镜头的种类和功能也在不断扩展&#xff0c;以适应各种复杂的监控环境和需求。对于相机成像来讲&#…

省级数字经济发展水平数据(2011-2022年)

数字经济是指以数据资源为关键要素&#xff0c;以现代信息网络为主要载体&#xff0c;以信息通信技术融合应用、全要素数字化转型为重要推动力&#xff0c;促进公平与效率更加统一的新经济形态。 2011-2022年省级数字经济发展水平数据&#xff08;&#xff09;.zip资源-CSDN文…

【WRF模拟】全过程总结:WPS预处理及WRF运行

【WRF模拟】全过程总结:WPS预处理及WRF运行 1 数据准备1.1 嵌套域设置(Customize domain)-基于QGis中gis4wrf插件1.2 静态地理数据1.2.1 叶面积指数LAI和植被覆盖度Fpar(月尺度)1.2.2 地面反照率(月尺度)1.2.3 土地利用类型+不透水面积1.2.4 数据处理:geotiff→tiff(W…

银行家算法(模拟)

银行家算法是一种避免死锁的有效算法&#xff0c;它借鉴了银行家贷款的策略。在分配资源之前&#xff0c;银行家会检查系统是否有足够的资源满足进程的最大需求&#xff0c;若有&#xff0c;则暂时分配资源&#xff0c;然后继续检查剩余资源是否足够满足其他进程的最大需求。只…

「QT」几何数据类 之 QSizeF 浮点型尺寸类

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「QT」QT5程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…

【动手学电机驱动】STM32-FOC(3)STM32 三路互补 PWM 输出

STM32-FOC&#xff08;1&#xff09;STM32 电机控制的软件开发环境 STM32-FOC&#xff08;2&#xff09;STM32 导入和创建项目 STM32-FOC&#xff08;3&#xff09;STM32 三路互补 PWM 输出 STM32-FOC&#xff08;4&#xff09;IHM03 电机控制套件介绍 STM32-FOC&#xff08;5&…

Spark中的shuffle

Shuffle的本质基于磁盘划分来解决分布式大数据量的全局分组、全局排序、重新分区【增大】的问题。 1、Spark的Shuffle设计 Spark Shuffle过程也叫作宽依赖过程&#xff0c;Spark不完全依赖于内存计算&#xff0c;面临以上问题时&#xff0c;也需要Shuffle过程。 2、Spark中哪…

ffmpeg 视频滤镜:屏蔽边框杂色- fillborders

滤镜描述 fillborders 官网链接 > FFmpeg Filters Documentation fillborders滤镜有几种方式帮你屏蔽边框的杂色、不好的图案。 滤镜使用 参数 left <int> ..FV.....T. set the left fill border (from 0 to INT_MAX) (default 0)right …

「C/C++」C++标准库 之 #include<iostream> 标准输入输出

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…

智能合约在供应链金融中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 智能合约在供应链金融中的应用 智能合约在供应链金融中的应用 智能合约在供应链金融中的应用 引言 智能合约概述 定义与原理 发展…