news 2026/4/21 11:57:38

孤儿进程与守护进程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
孤儿进程与守护进程

文章目录

  • 孤儿进程
    • 孤儿进程的含义
    • 制造孤儿进程
    • 孤儿进程的特点
    • 为什么需要孤儿进程机制
    • 孤儿进程的管理
      • 查找孤儿进程
      • 监控孤儿进程
      • 正确处理孤儿进程
  • 守护进程
    • 实现守护进程
      • 脱离终端
      • 关闭stdio流
      • 设置umask
      • 设置工作路径
  • 孤儿进程 vs 僵尸进程 vs 守护进程

孤儿进程

孤儿进程的含义

  • 父进程先于子进程终止,子进程成为孤儿进程,被 init 进程收养
  • 通俗比喻:
    • 就像父母双亡的孩子被政府(init进程)收养:
    • 父进程先死了
    • 子进程还活着
    • 被 init进程(PID=1) 收养
    • 继续正常运行
正常进程 → 父进程死亡 → 变成孤儿 → 被init收养 → 正常结束 (父母死了) (无父) (政府收养) (正常生活)

早期Linux是由init进程直接管理它,Ubuntu并不是由 init进程 接管的

而是由一个systemd接管的

init实际执行的就是systemd,因此被systemd的进程收养的孤儿进程,相当于被 init收养了

  • 是守护进程的基础

制造孤儿进程

  • test.c
#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/types.h>intmain(){pid_tpid=fork();if(pid==0){// 子进程printf("子进程 PID=%d 启动\n",getpid());printf("子进程的父进程 PID=%d\n",getppid());// 子进程睡眠5秒,等父进程先死sleep(5);printf("5秒后...\n");printf("子进程 PID=%d 还在运行\n",getpid());printf("现在的父进程 PID=%d (应该是1)\n",getppid());sleep(5);// 再运行一段时间printf("子进程结束\n");}else{// 父进程printf("父进程 PID=%d 创建了子进程 %d\n",getpid(),pid);printf("父进程立即结束\n");// 父进程立即退出,子进程变成孤儿exit(0);}return0;}

孤儿进程的特点

  • 父进程变成 init(PID=1)
# 运行以上的程序,然后用另一个终端查看 $ ps aux | grep -E "PID|孤儿进程的程序名" # 可以看到子进程的PPID(父进程ID)变成了1
  • 完全正常运行
    • 继续执行代码
    • 占用系统资源
    • 可以被信号控制
    • 正常退出时会被 init 回收
  • 与僵尸进程的区别
僵尸进程先于父进程结束便于父进程读取进程退出的状态
孤儿进程后于父进程结束常用于创建守护进程

为什么需要孤儿进程机制

  • 保证进程不会失去管理
// 如果没有孤儿进程收养机制:// 父进程死亡 → 子进程变成"野进程" → 无法被管理 → 资源泄漏// 有了收养机制:// 父进程死亡 → init收养 → 正常管理 → 资源正确释放
  • init进程的责任
# init进程(PID=1)是系统所有进程的祖先进程 # 它的责任包括: # 1. 收养所有孤儿进程 # 2. 等待孤儿进程结束 # 3. 回收孤儿进程资源

孤儿进程的管理

查找孤儿进程

# 方法1:使用ps查看PPID=1的进程ps-eo pid,ppid,pgid,sid,cmd|awk'$2 == 1 && $1 != 1'# 方法2:查找被init收养的进程ps-ef|awk'$3 == 1 && $2 != 0'# 方法3:使用pstree查看进程树pstree -p|grep-A5-B5"init"

监控孤儿进程

#!/bin/bash# monitor_orphans.sh - 监控孤儿进程whiletrue;doecho"=== 检查孤儿进程$(date)==="# 查找孤儿进程orphan_count=$(ps-eo pid,ppid,cmd|awk'$2 == 1 && $1 != 1'|wc-l)if[$orphan_count-gt0];thenecho"发现$orphan_count个孤儿进程:"ps-eo pid,ppid,user,cmd,start_time --sort=-start_time|awk'$2 == 1 && $1 != 1'echo"详细信息:"forpidin$(ps-eo pid,ppid|awk'$2 == 1 && $1 != 1 {print $1}');doecho"进程$pid:"echo" 运行时间:"$(ps-oetime=-p $pid)echo" 内存使用:"$(ps-orss=-p $pid)"KB"echo" CPU使用:"$(ps-o %cpu=-p $pid)"%"# 检查是否正常ifkill-0$pid2>/dev/null;thenecho" 状态:运行正常"elseecho" 状态:已结束"fiecho"---"doneelseecho"没有发现孤儿进程"fiecho""sleep60# 每分钟检查一次done

正确处理孤儿进程

  • // 如果发现孤儿进程异常,可以:
#include<stdio.h>#include<stdlib.h>#include<signal.h>#include<unistd.h>intmain(){// 方法1:优雅地终止孤儿进程pid_torphan_pid=1234;// 假设的孤儿进程PID// 先尝试友好终止if(kill(orphan_pid,SIGTERM)==0){printf("已发送SIGTERM给进程 %d\n",orphan_pid);// 等待一段时间sleep(5);// 检查是否还在运行if(kill(orphan_pid,0)==0){printf("进程 %d 还在运行,发送SIGKILL\n",orphan_pid);kill(orphan_pid,SIGKILL);}else{printf("进程 %d 已终止\n",orphan_pid);}}else{printf("进程 %d 不存在或无法终止\n",orphan_pid);}return0;}

守护进程

  • 守护程序是在后台运行并监督系统或向其他进程提供功能的服务进程
  • 利用孤儿进程被init收养这一机制实现一个守护进程

实现守护进程

脱离终端

if(fork()>0)exit(0);//进程组首进程不能成为会话首进程,所以这一步很关键setsid();//成立一个会话

关闭stdio流

close(0);close(1);close(2);

或者

close(STDIN_FILENO);close(STDOUT_FILENO);close(STDERR_FILENO);

设置umask

#include<sys/types.h>#include<sys/stat.h>mode_tumask(mode_tmask);

umask()的调用总会成功,并返回进程的前一umask

#include<stdio.h>#include<sys/stat.h>#include<sys/types.h>intmain(intargc,constchar*argv[]){umask(0222);//设置本进程的umask//由于后面不再做任何事所以这里省略了错误判断mkdir("/home/linux/process/tmp_mkdir",0777);perror("mkdir");//提示目录文件是否创建成功return0;}

设置工作路径

if(-1==chdir("/")){perror("chdir");exit(EXIT_FAILURE);}

孤儿进程 vs 僵尸进程 vs 守护进程

特性孤儿进程僵尸进程守护进程
父进程状态已终止未调用wait()已终止(故意)
进程状态运行中已终止运行中
占用资源正常占用占用PID,不占内存正常占用
能否被杀死可以不可以可以
回收者init进程父进程init进程
产生方式父进程先死父进程不wait故意fork两次
是否正常正常现象程序bug设计如此
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 18:22:22

CUDA安装路径错误排查:Miniconda-Python3.9镜像环境变量说明

CUDA安装路径错误排查&#xff1a;Miniconda-Python3.9镜像环境变量说明 在深度学习项目开发中&#xff0c;一个看似简单的问题——“CUDA不可用”——常常让开发者耗费数小时排查。尤其是在使用 Miniconda 搭建 Python 3.9 环境时&#xff0c;即便系统已正确安装 NVIDIA 驱动和…

作者头像 李华
网站建设 2026/4/19 22:31:55

【slime】RL MTP加速ROLLOUT

您提的问题非常精准&#xff0c;直击要害&#xff01;我明白您的困惑了。您是说&#xff1a;“你只是切断了 Embedding 那一头的梯度&#xff0c;但 LM Head 是在 MTP 计算流程的末端被使用的&#xff0c;梯度是从 mtp_loss -> mtp_logits -> LM_Head 这样反向流的&#…

作者头像 李华
网站建设 2026/4/18 10:59:47

langchain4j 构建循环工作流

一.背景 1. 技术背景:LLM 应用从 “单次交互” 到 “闭环执行” 的升级 随着大语言模型(LLM)在企业级场景落地深化,单纯的 “提问 - 回答” 式单次 LLM 调用已无法满足复杂业务需求 —— 金融科技、企业服务等领域需要的是「能自主完成多轮任务、持续迭代直至达成目标」的…

作者头像 李华
网站建设 2026/4/18 3:34:50

线索二叉树在C#里怎么用?提升遍历效率的秘诀

在数据结构的学习与应用中&#xff0c;线索二叉树是一种巧妙利用空指针域来优化遍历效率的存储结构。它能在不增加额外存储空间的前提下&#xff0c;提供对二叉树中结点的线性前驱与后继的直接访问&#xff0c;尤其适用于需要频繁遍历且对性能有要求的场景。掌握线索二叉树的构…

作者头像 李华
网站建设 2026/4/17 12:13:24

cimage类压缩图片:怎么选格式、调参数不损画质?

对数字图像进行处理时&#xff0c;文件体积与视觉质量的平衡是关键。cimage类压缩图片如何平衡画质与大小 cimage类压缩图片怎么保证清晰度 在实际使用cimage类库进行图片压缩时&#xff0c;清晰度主要取决于压缩算法和参数设置。例如&#xff0c;调整压缩因子或选择特定的采样…

作者头像 李华