Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Linux: 关于 SIGCHLD 的更多细节

Linux: 关于 SIGCHLD 的更多细节

作者头像
Lin_R
发布于 2018-10-22 06:39:21
发布于 2018-10-22 06:39:21
2.9K00
代码可运行
举报
文章被收录于专栏:技术栈大杂烩技术栈大杂烩
运行总次数:0
代码可运行

僵尸进程

何为僵尸进程?

一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用 wait 或 waitpid 获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程

成为僵尸进程的因素
  1. 子进程 先于 父进程退出;
  2. 子进程的状态信息,没有被父进程回收;

那么问题来了,子进程退出了,父进程怎么知道呢?

对该机制有稍微了解的话,不难得知一个关键因素:SIGCHLD。正是这个SIGCHLD起到了通知的作用,所以后面的处理也是基于它而实现。

僵尸进程处理方案
  1. 父进程捕获 SIGCHLD 信号,则显示调用 waitwaitpid
  2. 父进程直接忽略该信号。signal(SIGCHLD, SIG_IGN),这样子进程直接会退出。 需要注意的是,虽然进程对于 `SIGCHLD`的默认动作是忽略,但是还是显示写出来,才能有效;
  3. 把父进程杀了,子进程直接过继给 init,由 init伺候着。 不用担心 init会挂着一堆僵尸, init本身的设计就有专门回收的处理,所以有多少回收多少;

SIGCHLD 还能干嘛

刚才我们在处理到父子进程相关的问题时,多多少少接触到SIGCHLD, 那么,只有在回收子进程的时候才需要用到么?感觉好浪费不是么?

别担心 ~ 这个作用肯定是不止这样的!

其实对于SIGCHLD,我们一般的理解是,子进程退出发送的信号,但其实不是的,这个信号代表的含义是:

子进程状态变更了,例如停止、继续、退出等,都会发送这个信号通知父进程。而父进程就能通过 wait/waitpid 来获悉这些状态了。

看起来有点意思,我们仿佛能借此做些有趣的事情了。

wait / waitpid 相关知识
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <sys/wait.h>
pid_t wait(int * statloc);
pid_t waitpid(pid_t pid,int *statloc,int options);

wait相对来说会常用点,因为不需要指定 pid,而waitpid就在一些需要指定特定pid时才会比较常见,那么它们之间的关系就真的是只是这样么?

其实wait是对waitpid的封装,专门用来回收子进程退出的信息,同样的,它简单粗暴的设置成了堵塞方式,如果没有任何子进程退出,那么就堵塞住。

waitpid功能非常强大,pidoptions都提供了非常灵活的用法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    pid:
         < -1: 取该 pid 的绝对值,如果任何子进程的进程组ID等于该值,则该进程组的任一子进程中的进程状态发生变化,都会触发`waitpid`的回调;
        == -1: 监听范围扩大到任意子进程,也就是 wait(status)==  0: 监听进程组ID和父进程一样的子进程;
         >  0: 监听该pid的子进程;

    options:
        WNOHANG: 调用时,指定的 pid 仍未结束运行,则 wait 立即返回 0WUNTRACED: 当子进程被暂停时,则立即返回子进程的 pid;
        WCONTINUED: 当被暂停的子进程,又被信号恢复时,则立即返回子进程的pid;

而下面这些宏,将搭配status一起使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
WIFEXITED(status): 当子进程调用 exit、_exit或者正常从 main 返回等正常结束时,返回 true 
    --> WEXITSTATUS(status): 获取上面的 exit_code
        
WIFSIGNALED(status): 当子进程被信号杀死时,返回 true--> WTERMSIG(status): 获取信号的值(int)

WIFSTOPPED(status): 当自己弄成被信号暂停执行时,返回 true--> WSTOPSIG(status): 获取该信号的值

WIFCONTINUED(status): 子进程接收到SIGCONT信号继续执行时,返回 true
最小实践

我们来个最小的 demo 来说明上面的怎么用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<stdio.h>
#include<string.h>
#include<signal.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
int main(){
    int pid;
    if((pid = fork()) == 0){
        while(1){
            printf("Child: %d\n", getpid());
            sleep(1);
        }
    }
    else{
        int status;
        pid_t w;
        while(1){
            // 希望堵塞,所以没用 WNOHANG
            w = waitpid(pid, &status,WCONTINUED | WUNTRACED);
            if(WIFEXITED(status)){
                printf("子进程正常退出,状态码: %d\n", WEXITSTATUS(status));
                exit(0);
            } else if(WIFSIGNALED(status)){
                printf("子进程被信号杀死了! 信号值: %d\n", WTERMSIG(status));
                exit(0);
            } else if(WIFSTOPPED(status)){
                printf("子进程被信号暂停了! 信号值: %d\n", WSTOPSIG(status));
            } else if(WIFCONTINUED(status)){
                printf("子进程又恢复继续运行了\n");
            }
        }
    }
}

终端输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Child: 10848
Child: 10848                    # 子进程的 pid

子进程被信号暂停了!信号值:21       # kill -SIGTTIN 10848
子进程又恢复继续运行了                # kill -SIGTTIN 10848
...
子进程被信号暂停了! 信号值: 19      # kill -SIGSTOP 10848
子进程又恢复继续运行了                # kill -SIGTTIN 10848   
...
子进程被信号杀死了! 信号值: 15      # kill -SIGTERM 10848    

如果自己在子进程上面加个退出,就会打印:正常退出了   

结语

在上面的实验中,我们已经发现通过SIGCHLD除了用来回收子进程,还能获悉子进程的状态!

在操作系统上,也有很多利用这个在工作的,例如:后台进程,如果向标准输入读取内容时,是会被暂停的

为什么呢?

因为后台进程,是和终端断开连接的,当它从标准输入读取内容时,终端的驱动程序会发现这个操作,会发一个 SIGTTIN 给后台进程,让其暂停,并且通知用户,只有用户通过 fg 命令将其转换成 前台进程时,才能继续工作

正是有这样的一套机制,所以我们也能做出很多比较实在的东西了~

欢迎各位大神指点交流, QQ讨论群: 258498217

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
[操作系统] 进程等待
进程等待(Process Waiting)是操作系统中父进程用于管理和同步子进程的重要机制。根据你的图片内容,我们可以分几个部分来讲解进程等待的相关知识。
DevKevin
2025/02/12
770
[操作系统] 进程等待
《Linux操作系统编程》 第六章 Linux中的进程监控: fork函数的使用,以及父子进程间的关系,掌握exec系列函数
使学生理解Linux中进程控制块的数据结构,Linux进程的创建、执行、终止、等待以及监控方法。并重点掌握fork函数的使用以及exec系列函数。
猫头虎
2024/04/08
2010
《Linux操作系统编程》 第六章 Linux中的进程监控: fork函数的使用,以及父子进程间的关系,掌握exec系列函数
Linux僵尸进程
版权声明:本文为博主原创文章,转载请注明博客地址: https://blog.csdn.net/zy010101/article/details/83715103
zy010101
2019/05/25
4.5K0
L010Linux和androidNDK之linux避免僵尸进程,子进程退出的处理
L010Linux和androidNDK之linux避免僵尸进程,子进程退出的处理
上善若水.夏
2018/09/28
3.2K0
和老李一起搞山寨Workerman(三)
今日清晨睡梦中醒来,已是7点40分有余。静躺在床上,耳边远处又断断续续萦绕着老人们在楼下的野园子里跟着于魁智吊嗓子的声音,时不时还夹杂着一段段抖空竹的风哨声。
老李秀
2019/12/11
1.1K0
和老李一起搞山寨Workerman(三)
【Linux信号】四:SIGCHLD信号
实际上,在子进程结束的时候,会产生一个SIGCHLD信号,信号描述如下,根据man手册可以知道,子进程结束运行,其父进程会收到SIGCHLD信号,该信号的默认处理动作是忽略。
mindtechnist
2024/08/08
2150
【Linux信号】四:SIGCHLD信号
【Linux探索学习】第十八弹——进程等待:深入解析操作系统中的进程等待机制
Linux学习笔记:https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482
GG Bond1
2024/12/04
1600
【Linux探索学习】第十八弹——进程等待:深入解析操作系统中的进程等待机制
【Linux进程控制】五、wait()函数——子进程回收
僵尸进程:子进程结束,父进程没有回收子进程的资源(PCB),这个资源必须要由父进程回收,否则就形成僵尸进程。
mindtechnist
2024/08/08
1170
【Linux进程控制】五、wait()函数——子进程回收
linux系统编程之进程(四):wait/waitpid函数与僵尸进程、fork 2 times
该文章介绍了如何在Linux系统中通过fork函数创建子进程,并详细讲解了fork函数的工作原理、父进程和子进程之间的通信以及fork函数引发的孤儿进程和僵尸进程等问题。同时,文章还介绍了如何使用wait和waitpid函数等待子进程结束,以及如何使用exec系列函数在子进程中执行新的程序。
s1mba
2018/01/03
3.4K0
僵尸进程的处理办法
在https://editor.csdn.net/md/?articleId=138925446这篇文章中,我缺失了关于僵尸进程的处理办法的内容,因为当时脑子不好的小菜鸟并未学到这里,现在就让我填上这个坑🕳吧😉
用户11039529
2024/05/24
720
僵尸进程的处理办法
OpenHarmony 内核源码分析(进程回收篇) | 进程关系链
进程是家族式管理的,父子关系,兄弟关系,朋友关系,子女关系,甚至陌生人关系(等待你消亡)在一个进程的生命周期中都会记录下来.用什么来记录呢?当然是内核最重要的胶水结构体LOS_DL_LIST,进程控制块(以下简称PCB)用了8个双向链表来记录进程家族的基因关系和运行时关系.如下:
小帅聊鸿蒙
2025/03/21
340
通过linux0.11理解僵尸进程
首先僵尸进程产生的原因是子进程退出了,但是父进程没有回收他的资源(pcb),所以我们从源头开始分析这个过程。那就是子进程退出的时候。进程是通过exit系统调用退出的。 我们看一下exit函数的代码。
theanarkh
2020/02/17
2K0
【Linux系统编程】七、进程等待
​ 之前我们讲过,子进程退出,父进程如果还在执行中,就会造成 “ 僵尸进程 ” 的问题,进而造成内存泄漏。另外,进程一旦变成僵尸状态,那就刀枪不入,“ 杀人不眨眼 ” 的 kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。 最后,父进程派给子进程的任务完成的如何,我们需要知道。如,子进程运行完成,结果对还是不对,或者是否正常退出。父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息。
利刃大大
2025/02/18
870
【Linux系统编程】七、进程等待
Linux进程管理命令及状态详解
查看进程树。 linux中,每一个进程都是由其父进程创建的。此命令以可视化方式显示进程,通过显示进程的树状图来展示进程间关系。如果指定了pid了,那么树的根是该pid,不然将会是init(pid: 1)。
bboy枫亭
2020/09/22
1.9K0
Linux进程管理命令及状态详解
深入理解计算机系统:进程
导语:这是篇读书笔记,每次重读CSAPP都有新的认知,尤其是在进入了后台通道之后才感受到每天和进程打交道的感觉是如此深刻。 0x00 What is Process? [ system structure ] 进程(Process) 经典定义是一个执行中的程序的实例,操作系统对一个正在运行的程序的一种抽象。并发运行,指的是一个进程的指令和另一个进程的指令交错执行。操作系统实现这种交错执行的机制称为上下文切换。 线程(Thread) 一个进程可以由多个线程的执行单元组成,每个线程都运行在进程的
腾讯技术工程官方号
2019/09/07
1.3K0
深入理解计算机系统:进程
【linux】进程等待与进程替换
任何子进程,在退出的情况下,一般必须要被父进程进行等待。进程在退出的时候,如果父进程不管不顾,退出进程,状态Z(僵尸状态),内存泄漏
用户11029103
2024/11/16
1100
【linux】进程等待与进程替换
Linux wait() 和 waitpid()函数介绍
转载自http://blog.csdn.net/wallwind/article/details/6998602 ---- 当一个进程正常或异常终止的时候,内核就像其父进程发送SIGCHLD信号,因为子进程是个一步事件,所以这种信号也是内核系那个父进程发的异步通知。父进程可以选择忽略该信号,或者提供一个该信号发生时即被调用执行的函数。对于这种信号的系统默认动作是忽略它。 现在要知道调用wait或waitpid的进程可能会发生什么情况:  如果其所有子进程都在运行,则阻塞。 如果一个子进程已经终止,正在得带的
老白
2018/03/19
2.5K0
Linux wait() 和 waitpid()函数介绍
僵尸进程
  在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等.但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination statu
猿人谷
2018/01/17
1.4K0
Linux进程控制——Linux进程等待
前言:接着前面进程终止,话不多说我们进入Linux进程等待的学习,如果你还不了解进程终止建议先了解:
Eternity._
2024/06/14
2280
Linux进程控制——Linux进程等待
Linux僵尸进程以及wait函数
僵尸进程就是已经结束的进程(几乎不占计算机资源),但是它并没有从进程列表中删除。僵尸进程太多会导致操作系统的进程数目过多,从而占满了OS的进程表。进而导致无法创建新进程,致使OS崩溃。
zy010101
2022/05/05
1.8K0
Linux僵尸进程以及wait函数
推荐阅读
相关推荐
[操作系统] 进程等待
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验