当前位置: 首页 > article >正文

关于【进程池阻塞 + 子进程未回收问题】

续接上文进程间通信二实现一个高可用的进程池-CSDN博客目录一、先看现象两个核心问题二、核心原因文件描述符泄漏管道读端没关干净1. 管道的核心规则回顾2. 后果管道写端永远关不完三、原理图解为什么子进程会继承父进程的文件描述符四、为什么子进程没被回收五、修复方案5.1 倒着关5.2 在子进程中关闭所有继承的管道写端这个关于进程池的demo 有一个致命的问题典型的「文件描述符泄漏导致管道读端未关闭 → 子进程阻塞 → 僵尸进程 / 无法回收」问题一、先看现象两个核心问题进程阻塞子进程卡在read上主进程也卡在waitpid上程序无法正常结束子进程未回收ps ajx | grep ProcessPool看到 6 个进程1 个父进程 5 个子进程说明子进程退出后变成了僵尸进程父进程没回收成功二、核心原因文件描述符泄漏管道读端没关干净1. 管道的核心规则回顾管道的read行为由所有写端是否关闭决定只要还有任意一个写端文件描述符没被关闭read就会一直阻塞不会返回 0EOF只有当所有写端都关闭时read才会返回 0子进程才会退出循环在ProcessPool::Start()中创建子进程和管道for (int i 0; i _process_num; i) { int pipefd[2] {0}; pipe(pipefd); pid_t subid fork(); if (subid 0) { close(pipefd[1]); // 子进程关写端 Work(pipefd[0]); // 子进程阻塞在 read(pipefd[0]) close(pipefd[0]); exit(0); } else { close(pipefd[0]); // 父进程关读端 _cm.Insert(pipefd[1], subid); // 父进程持有写端 } }问题出在子进程会继承父进程之前创建的所有管道文件描述符第 1 次循环父进程创建管道 1 → fork 子进程 1 → 子进程 1 继承管道 1 的读 / 写端第 2 次循环父进程创建管道 2 → fork 子进程 2 → 子进程 2继承管道 1 的写端 管道 2 的读 / 写端第 3 次循环父进程创建管道 3 → fork 子进程 3 → 子进程 3继承管道 1 的写端 管道 2 的写端 管道 3 的读 / 写端... 以此类推第 5 个子进程会继承前 4 个管道的所有写端2. 后果管道写端永远关不完当你调用Stop()关闭父进程持有的所有写端时父进程的写端都关了但子进程手里还握着之前管道的写端对管道 1 来说子进程 2~5 都持有它的写端 → 管道 1 的写端总数 0子进程 1 调用read(pipefd[0])时发现还有写端没关 →一直阻塞不会退出父进程调用waitpid时子进程还活着 →主进程也阻塞最终所有子进程都卡在read父进程卡在waitpid程序僵死三、原理图解为什么子进程会继承父进程的文件描述符四、为什么子进程没被回收因为子进程根本没退出子进程阻塞在read没有执行exit(0)父进程调用waitpid时子进程还在运行 →waitpid会一直阻塞只有当子进程真正退出后父进程才能回收它否则就会一直等下去如果子进程意外退出父进程没回收才会变成僵尸进程Z 状态这里是子进程活着父进程阻塞本质是死锁。五、修复方案5.1 倒着关5.2 在子进程中关闭所有继承的管道写端#ifndef __PROCESS_POOL_HPP__ #define __PROCESS_POOL_HPP__ #include iostream #include vector #include unistd.h #include cstdlib #include sys/wait.h #include Task.hpp // 先描述 class Channel { public: Channel(int fd, pid_t id) : _wfd(fd), _subid(id) { _name channel- std::to_string(_wfd) - std::to_string(_subid); } ~Channel() { } void Send(int code) { int n write(_wfd, code, sizeof(code)); (void)n; // n被定义如果未使用的时候会出现告警 } void Close() { close(_wfd); } void Wait() { pid_t rid waitpid(_subid, nullptr, 0); (void)rid; } int Fd() { return _wfd; } pid_t SubId() { return _subid; } std::string Name() { return _name; } private: int _wfd; pid_t _subid; // 想知道这个信道是给哪一个子进程的 std::string _name; }; // 再组织 class ChannelManager { public: ChannelManager() : _next(0) {} void Insert(int wfd, pid_t subid) { _channels.emplace_back(wfd, subid); // 不用再构建临时变量 // Channel c(wfd,subid); // _channels.push_back(std::move(c)); } Channel Select() { auto c _channels[_next]; _next; // 下一次访问的时候就去访问下一个了 _next % _channels.size(); return c; } void PrintfChannel() { for (auto channel : _channels) { std::cout channel.Name() std::endl; } } void CloseAll() { for(auto channel : _channels) { channel.Close(); } } void StopSubProcess() { for (auto channel : _channels) { channel.Close(); std::cout 关闭: channel.Name() std::endl; } } void WaitSubProcess() { for (auto channel : _channels) { channel.Wait(); std::cout 回收: channel.Name() std::endl; } } void CloseAndWait() { //解决方案2 for(auto channel : _channels) { channel.Close(); std::cout 关闭: channel.Name() std::endl; channel.Wait(); std::cout 回收: channel.Name() std::endl; } // 解决方案1倒着关 // for (int i _channels.size() - 1; i 0; i--) // { // _channels[i].Close(); // std::cout 关闭: _channels[i].Name() std::endl; // _channels[i].Wait(); // std::cout 回收: _channels[i].Name() std::endl; // } } ~ChannelManager() {} private: std::vectorChannel _channels; int _next; }; const int gdefaultnum 5; class ProcessPool { public: ProcessPool(int num) : _process_num(num) { _tm.Register(PrintLog); _tm.Register(Downlode); _tm.Register(Uplode); } void Work(int rfd) { while (true) { int code 0; ssize_t n read(rfd, code, sizeof(code)); if (n 0) { if (n ! sizeof(code)) { continue; } std::cout 子进程[ getpid() ]收到了一个任务码: code std::endl; _tm.Execute(code); } else if (n 0) { std::cout 子进程退出 std::endl; break; } else { std::cout 读取错误 std::endl; break; } // std::cout 我是子进程,我的rfd是: rfd std::endl; // sleep(5); } } bool Start() { for (int i 0; i _process_num; i) { // 1.创建管道 int pipefd[2] {0}; int n pipe(pipefd); if (n 0) return false; // 2.创建子进程 pid_t subid fork(); if (subid 0) return false; else if (subid 0) { // 子进程 //让子进程关闭自己继承下来的 他的哥哥进程的w端关闭就行了 //for(std::vectorChannel _channels) _channels.close(); _cm.CloseAll(); // 3.关闭不需要的文件描述符 close(pipefd[1]); Work(pipefd[0]); close(pipefd[0]); exit(0); } else { // 父进程 // 3.关闭不需要的文件描述符 close(pipefd[0]); // 写端: pipefd[1]; _cm.Insert(pipefd[1], subid); // wfd,subid, } } return true; } void Debug() { _cm.PrintfChannel(); } void Run() { // 1.选择了一个任务 int taskcode _tm.Code(); // 2.选择一个信道【子进程】负载均衡的选择一个子进程完成任务 auto c _cm.Select(); std::cout 选择了一个子进程 c.Name() std::endl; // 3.发送任务 c.Send(taskcode); std::cout 发送了一个任务码 c.Name() std::endl; } void Stop() { _cm.CloseAndWait(); // // 关闭父进程所有的wfd即可 // _cm.StopSubProcess(); // // 回收所有子进程 // _cm.WaitSubProcess(); } ~ProcessPool() {} private: ChannelManager _cm; int _process_num; // 创建对应的进程个数 TaskManager _tm; // }; #endif

相关文章:

关于【进程池阻塞 + 子进程未回收问题】

续接上文:进程间通信(二):实现一个高可用的进程池-CSDN博客 目录 一、先看现象:两个核心问题 二、核心原因:文件描述符泄漏(管道读端没关干净) 1. 管道的核心规则回顾 2. 后果&a…...

QMCDecode终极指南:3步破解QQ音乐加密格式,实现音频自由播放

QMCDecode终极指南:3步破解QQ音乐加密格式,实现音频自由播放 【免费下载链接】QMCDecode QQ音乐QMC格式转换为普通格式(qmcflac转flac,qmc0,qmc3转mp3, mflac,mflac0等转flac),仅支持macOS,可自动识别到QQ音乐下载目录…...

Spring_couplet_generation 助力科研:使用MATLAB进行生成结果的数据分析与可视化

Spring_couplet_generation 助力科研:使用MATLAB进行生成结果的数据分析与可视化 1. 引言 想象一下,你是一位研究语言文化或社会科学的学者,最近利用AI模型生成了成千上万副春联。面对这海量的文本数据,你可能会感到既兴奋又头疼…...

能耗优化指南:OpenClaw+GLM-4.7-Flash笔记本续航方案

能耗优化指南:OpenClawGLM-4.7-Flash笔记本续航方案 1. 为什么需要关注OpenClaw的能耗问题 去年夏天的一次出差经历让我深刻意识到这个问题的重要性。当时我正在高铁上用笔记本调试一个OpenClaw自动化流程,结果不到两小时就收到了电量不足的警告。这促…...

Qwen3-4B-Instruct-2507问题解决:部署中常见的5个错误及快速修复方法

Qwen3-4B-Instruct-2507问题解决:部署中常见的5个错误及快速修复方法 1. 部署准备与环境检查 在开始部署Qwen3-4B-Instruct-2507模型之前,确保您的环境满足以下基本要求: 硬件配置:推荐使用NVIDIA 4090D显卡(24GB显…...

Apex Legends压枪宏终极指南:轻松掌握自动武器检测与精准射击

Apex Legends压枪宏终极指南:轻松掌握自动武器检测与精准射击 【免费下载链接】Apex-NoRecoil-2021 Scripts to reduce recoil for Apex Legends. (auto weapon detection, support multiple resolutions) 项目地址: https://gitcode.com/gh_mirrors/ap/Apex-NoRe…...

终极指南:如何免费将CAJ文件转换为高质量PDF?caj2pdf完整使用教程

终极指南:如何免费将CAJ文件转换为高质量PDF?caj2pdf完整使用教程 【免费下载链接】caj2pdf Convert CAJ (China Academic Journals) files to PDF. 转换中国知网 CAJ 格式文献为 PDF。佛系转换,成功与否,皆是玄学。 项目地址: …...

一文讲清楚 OpenClaw 是什么,以及 Windows 下的部署

OpenClaw 到底是什么1. 它在系统里干的事:接入层 运行时管理很多人第一次看到 OpenClaw,会把它当成“一个聊天 UI”。更工程化的视角是:它负责把外部请求接进来,并把后面的执行系统跑起来、管起来。接入层:把外部入口…...

Wan2.2-I2V-A14B开源大模型:支持LoRA微调与私有领域视频风格迁移

Wan2.2-I2V-A14B开源大模型:支持LoRA微调与私有领域视频风格迁移 1. 模型概述与核心能力 Wan2.2-I2V-A14B是一款开源的文生视频大模型,专为高质量视频生成任务设计。该模型在保持开源特性的同时,通过LoRA微调技术实现了对私有领域视频风格的…...

人脸识别OOD模型在医疗领域的应用探索

人脸识别OOD模型在医疗领域的应用探索 1. 引言 在医院里,每天都有成千上万的患者需要身份确认、用药核对和病情监测。传统的医疗身份验证方式如手环、身份证件等存在被冒用、丢失或信息错误的风险。而医护人员在繁忙的工作中,也可能因为疲劳或疏忽而错…...

Flux Sea Studio 入门:十分钟完成星图平台镜像部署并生成首张图片

Flux Sea Studio 入门:十分钟完成星图平台镜像部署并生成首张图片 想试试最近很火的AI绘画,但又觉得本地部署太麻烦,显卡要求太高?今天咱们就来聊聊一个超级省事的办法——直接在云端用Flux Sea Studio。你不需要懂代码&#xff…...

AI Agent开发实战:基于PyTorch与LangChain构建自主任务执行智能体

AI Agent开发实战:基于PyTorch与LangChain构建自主任务执行智能体 1. 为什么需要自主任务执行智能体 想象一下,你每天要处理几十封邮件、查找各种资料、整理会议纪要,还要写周报。这些重复性工作占据了大量时间,而真正需要创造力…...

别再手动填Excel了!用Java+Spire.XLS 15.6.3实现批量报表自动化(附完整源码)

Java报表自动化革命:Spire.XLS实战指南与生产力跃迁 凌晨三点的办公室,最后一份月度销售报表终于核对完毕。这样的场景是否似曾相识?据统计,全球超过70%的企业级数据仍通过Excel流转,而其中近40%的时间消耗在机械化的…...

革新性B站用户分析工具:智能解析评论区用户背景的终极方案

革新性B站用户分析工具:智能解析评论区用户背景的终极方案 【免费下载链接】bilibili-comment-checker B站评论区自动标注成分,支持动态和关注识别以及手动输入 UID 识别 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-comment-checker …...

AMD Ryzen硬件调试工具实战指南:从问题诊断到系统优化

AMD Ryzen硬件调试工具实战指南:从问题诊断到系统优化 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https://gi…...

300FPS的实时目标跟踪是怎么炼成的?手把手拆解KCF算法里的数学魔法

300FPS实时目标跟踪背后的数学魔法:KCF算法深度解密 在计算机视觉领域,实时目标跟踪一直是个令人着迷又充满挑战的问题。想象一下,当你在观看一场足球比赛时,摄像机需要实时锁定某个球员;或者当自动驾驶汽车行驶时&am…...

解锁桌面音乐新体验:LyricsX让你的Mac成为私人KTV

解锁桌面音乐新体验:LyricsX让你的Mac成为私人KTV 【免费下载链接】Lyrics Swift-based iTunes plug-in to display lyrics on the desktop. 项目地址: https://gitcode.com/gh_mirrors/lyr/Lyrics 还在为听歌时找不到歌词而烦恼吗?LyricsX这款基…...

如何在Python中正确调用DeepSeek-Reasoner获取思考过程(附完整代码示例)

深度解析:Python调用DeepSeek-Reasoner获取思维链的工程实践 当开发者需要构建具备复杂推理能力的AI应用时,获取模型完整的思考过程(Reasoning Content)往往比最终答案更有价值。DeepSeek-Reasoner作为专为逻辑推理优化的模型&…...

PMSM无感控制中滑模观测器的相位补偿与抖振优化

1. 滑模观测器在PMSM无感控制中的核心作用 永磁同步电机(PMSM)的无位置传感器控制技术中,滑模观测器(SMO)扮演着关键角色。这种控制方式不需要物理位置传感器,而是通过算法实时估算转子位置和速度。我在实…...

如何解决健康160抢号难题?智能工具91160-cli让挂号效率提升5倍

如何解决健康160抢号难题?智能工具91160-cli让挂号效率提升5倍 【免费下载链接】91160-cli 健康160全自动挂号脚本 项目地址: https://gitcode.com/gh_mirrors/91/91160-cli 你是否曾遇到预约专家号时页面卡顿,等刷新完成号源已被抢空&#xff1f…...

【方案、开源】从零到国一:空地协同消防无人机系统全栈技术解析

1. 空地协同消防无人机系统设计思路 第一次接触这个项目时,我和很多同学一样感到无从下手。直到把整个系统拆解成几个核心模块,思路才逐渐清晰。这个系统的关键在于"空地协同"四个字,简单说就是让无人机和小车像两个配合默契的消防…...

LFM2.5-1.2B-Thinking多模态扩展展示:结合视觉模型的图文理解能力

LFM2.5-1.2B-Thinking多模态扩展展示:结合视觉模型的图文理解能力 1. 多模态能力惊艳亮相 LFM2.5-1.2B-Thinking最近在多模态领域展现出了令人惊喜的表现。这个原本专注于文本推理的模型,通过与视觉模型的结合,实现了从纯文本到图文理解的跨…...

YOLOv8模型训练避坑指南:GTX16系列显卡兼容性问题解决方案

GTX16系列显卡用户必读:YOLOv8模型训练全流程避坑手册 当你在GTX16系列显卡上运行YOLOv8训练脚本时,是否遇到过这样的场景:训练过程看似正常,但最终输出的P(精确率)、R(召回率)、mAP…...

深度解析OpenCode插件架构:构建企业级AI助手扩展平台

深度解析OpenCode插件架构:构建企业级AI助手扩展平台 【免费下载链接】opencode 一个专为终端打造的开源AI编程助手,模型灵活可选,可远程驱动。 项目地址: https://gitcode.com/GitHub_Trending/openc/opencode 在当今AI驱动的开发环境…...

设备重生:面向企业IT的激活锁解决方案

设备重生:面向企业IT的激活锁解决方案 【免费下载链接】applera1n icloud bypass for ios 15-16 项目地址: https://gitcode.com/gh_mirrors/ap/applera1n 问题诊断:激活锁困局与商业价值损失 企业设备管理的隐形成本 某教育机构IT主管王工近期…...

用tcpreplay+Wireshark搭建网络攻防实验环境:手把手教你复现渗透测试流量

实战指南:用tcpreplay与Wireshark构建网络攻防实验环境 在网络安全领域,理论知识的掌握固然重要,但真正的技能提升往往来自于实战演练。然而,直接在真实网络环境中进行渗透测试或攻击模拟不仅存在法律风险,还可能对生…...

LumiPixel模型API接口调用详解:Python/Node.js快速集成

LumiPixel模型API接口调用详解:Python/Node.js快速集成 1. 前言:为什么选择API集成 如果你正在开发一个需要AI生成能力的应用,直接调用现成的模型API可能是最高效的方式。LumiPixel Canvas Quest模型提供了简单易用的API接口,让…...

GuwenBERT:古文理解的新纪元,让AI读懂千年典籍的智慧

GuwenBERT:古文理解的新纪元,让AI读懂千年典籍的智慧 【免费下载链接】guwenbert GuwenBERT: 古文预训练语言模型(古文BERT) A Pre-trained Language Model for Classical Chinese (Literary Chinese) 项目地址: https://gitcod…...

3步彻底解决Visual C++运行库问题:告别DLL缺失和应用崩溃

3步彻底解决Visual C运行库问题:告别DLL缺失和应用崩溃 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist Visual C Redistributable(微软Vi…...

FireRedASR-AED-L语音识别模型WebUI快速部署教程:Python环境一键配置

FireRedASR-AED-L语音识别模型WebUI快速部署教程:Python环境一键配置 语音识别技术正在快速融入我们的日常开发,无论是做智能客服、会议纪要,还是内容审核,一个好用的识别模型都能省下大量时间。但很多朋友在第一步——环境部署上…...