阿里高并发编程进阶小册(终极版)全网首次公开!

核心内容摘要

零基础高效部署开源机器人框架:多协议QQ机器人5分钟实施指南
前端视频处理实践解析:基于MP4Box.js的FastStart模式检测技术指南

DID实战指南:从平行趋势检验到PSM-DID的Stata全流程解析

❤️燃于AC之乐 来自重庆 计算机专业的一枚大学生✨专注 C/C Linux 数据结构 算法竞赛 AI️志同道合的人会看见同一片风景点击进入作者专栏《算法画解》✅《linux系统编程》✅《C》✅《算法画解》算法相关题目点击即可进入实操感兴趣的可以先收藏起来请多多支持还有大家有相关问题都可以给我留言咨询希望希望共同交流心得一起进步你我陪伴学习路上不孤单文章目录前言

进程创建——fork函数解析

1 fork 函数基础

2 fork 的工作原理

3 写时拷贝技术

4 fork 的典型应用场景

5 fork 失败原因⏹️

进程终止机制

1 进程退出场景

2 退出状态码

3 退出函数对比

进程等待的必要性

1 僵尸进程问题

2 信息获取需求✨

进程等待方法

1 wait() 函数

2 waitpid() 函数

3 状态信息解析

4 阻塞与非阻塞等待

5 实践建议前言在Linux系统编程中进程管理是并发与并行的基石。

进程的生命周期包含创建、执行、终止与回收每个环节都直接影响程序的健壮性与系统效率。

本文聚焦进程控制的三大核心进程创建剖析fork的分身机制进程终止详解程序退出与资源清理进程等待解析僵尸进程防治与状态获取。

通过代码示例与原理结合助你深入理解父子进程协作掌握编写稳定高效多进程程序的必备技能。

无论你是系统编程新手还是经验开发者本文都将为你提供实用的技术指南和最佳实践。

进程创建——fork函数解析

1 fork 函数基础fork() 是 Linux 中创建新进程的核心函数它会从现有进程父进程复制出一个新进程子进程。

#includeunistd.hpid_tfork(void);返回值特性子进程返回 0 父进程返回子进程的 PID出错返回 -1。

2 fork 的工作原理为什么有两个返回值 fork() 的特殊之处在于它返回两次内核完成进程复制后系统中存在两个几乎相同的进程两个进程都从 fork() 调用处继续执行内核通过设置不同的返回值来区分父子进程。

返回值设计的合理性 子进程返回 0子进程可以轻松判断自己的身份if (pid

父进程返回子进程 PID父进程需要管理子进程必须知道其标识符这种设计让两个进程都能获得必要的信息且代码逻辑清晰。

内核执行步骤 分配新的内存块和内核数据结构给子进程 复制父进程的数据结构内容至子进程将子进程添加到系统进程列表fork() 返回调度器开始调度。

3 写时拷贝技术

关键技术特点父子进程代码共享初始数据也共享。

当任一进程试图写入数据时触发写时拷贝。

操作系统为写入方创建数据副本实现进程隔离。

优势提高内存使用效率延迟分配。

保证进程独立性。

减少不必要的内存复制。

4 fork 的典型应用场景任务并行处理父进程创建子进程处理不同任务。

服务器编程父进程监听连接子进程处理请求。

程序替换子进程调用 exec 执行新程序。

5 fork 失败原因系统进程数达到上限。

用户进程数超过限制。

内存资源不足。

⏹️

进程终止机制

1 进程退出场景代码正常执行完毕结果正确代码正常执行完毕结果错误代码异常终止如信号中断

2 退出状态码0执行成功非0执行失败具体数值表示错误类型使用echo $?查看上一个命令的退出码

3 退出函数对比_exit() 函数:#includeunistd.hvoid_exit(intstatus);直接终止进程立即进入内核,仅低8位状态码传递给父进程exit() 函数:#includestdlib.hvoidexit(intstatus);执行顺序

调用用户注册的清理函数atexit()

刷新所有I/O缓冲区

调用 _exit() 进入内核

return 退出main() 函数中的 return n 等价于 exit(n)

由运行时库处理返回值传递

进程等待的必要性

1 僵尸进程问题子进程退出后父进程不回收会产生僵尸进程僵尸进程占用系统资源导致内存泄漏即使使用 kill -9 也无法清除僵尸进程

2 信息获取需求父进程需要知道子进程是否正常结束子进程的退出状态子进程的执行结果。

进程等待方法

1 wait() 函数#includesys/wait.hpid_twait(int*status);阻塞等待任意子进程退出通过 status 获取子进程退出信息

2 waitpid() 函数pid_twaitpid(pid_tpid,int*status,intoptions);参数说明pid指定等待的进程ID-1 表示任意子进程status输出型参数存储退出状态options等待选项0为阻塞WNOHANG为非阻塞

3 状态信息解析wait和waitpid都有⼀个status参数该参数是⼀个输出型参数由操作系统填充。

如果传递NULL表示不关心子进程的退出状态信息。

否则操作系统会根据该参数将自进程的退出信息反馈给父进程。

status不能简单的当作整形来看待可以当作位图来看待具体细节如下图status 参数按位图解析低7位信号编号异常终止时第8位core dump 标志高8位退出状态码正常终止时关键宏WIFEXITED(status)判断是否正常退出WEXITSTATUS(status)提取退出码WIFSIGNALED(status)判断是否信号终止WTERMSIG(status)提取信号编号

4 阻塞与非阻塞等待阻塞等待父进程暂停执行直到子进程退出简单易用适合顺序执行场景。

阻塞等待方式intmain(){pid_tpid;pidfork();if(pid

{printf(%s fork error\n,__FUNCTION__);return1;}elseif(pid

{//childprintf(child is run, pid is : %d\n,getpid());sleep(

;exit(

;}else{intstatus0;pid_tretwaitpid(-1,status,

;//阻塞式等待等待5Sprintf(this is test for wait\n);if(WIFEXITED(status)retpid){printf(wait child5s success,childreturncode is:%d.\n,WEXITSTATUS(status));}else{printf(wait child failed, return.\n);return1;}}return0;}非阻塞等待使用 WNOHANG 选项立即返回不等待子进程适合需要同时处理其他任务的场景需要循环检查子进程状态。

进程的非阻塞等待方式#includestdio.h#includestdlib.h#includesys/wait.h#includeunistd.h#includevectortypedefvoid(*handler_t)();// 函数指针类型std::vectorhandler_thandlers;// 函数指针数组voidfun_one(){printf(这是⼀个临时任务1\n);}voidfun_two(){printf(这是⼀个临时任务2\n);}voidLoad(){handlers.push_back(fun_one);handlers.push_back(fun_two);}voidhandler(){if(handlers.empty())Load();for(autoiter:handlers)iter();}intmain(){pid_tpid;pidfork();if(pid

{printf(%s fork error\n,__FUNCTION__);return1;}elseif(pid

{// childprintf(child is run, pid is : %d\n,getpid());sleep(

;exit(

;}else{intstatus0;pid_tret0;do{retwaitpid(-1,status,WNOHANG);// ⾮阻塞式等待if(ret

{printf(child is running\n);}handler();}while(ret

;if(WIFEXITED(status)retpid){printf(wait child 5s success, child return code is :%d.\n,WEXITSTATUS(status));}else{printf(wait child failed, return.\n);return1;}}return0;}

5 实践建议

及时回收子进程避免僵尸进程积累

合理选择等待方式根据业务需求选择阻塞/非阻塞

检查退出状态不要忽略子进程的执行结果

处理异常情况考虑子进程异常终止的场景

资源清理确保子进程释放所有分配的资源。

通过合理使用 fork()、wait()/waitpid() 以及正确处理进程退出可以构建稳定可靠的并发程序。

理解进程创建、终止和等待的机制是 Linux 系统编程的重要基础。

加油志同道合的人会看到同一片风景。

看到这里请点个赞关注如果觉得有用就收藏一下吧。

后续还会持续更新的。

创作不易还请多多支持

9·1视频在线观看nba-9·1视频在线观看应用

百度百家号客服电话人工服务

123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123