Linux:fork()回收进程、wait()、waitpid()详解

fork和进程

1. fork创建子进程。

  1. 验证fork可以创建父子进程
      如下两个现象:
    a. fork之后,有两个pid。
    请添加图片描述

请添加图片描述
发现有两个进程,两个pid,一个输出的ppid是另外一个的pid,其实这就是父子进程。
b. 根据fork的返回值不同,if和else均可执行。
请添加图片描述
请添加图片描述
  ret>0的是父进程,<0的是子进程,可以通过fork创建子进程,然后让父子进程做不同的事。而创建进程失败返回的ret<0。

2.查看某特定pid的进程:

请添加图片描述
  这里是父进程的父进程,发现是bash【命令行处理器】,很好理解,创建父进程的bash命令行。

3. 关于进程的一些知识点【回忆】:

1. 进程的本质

  1. 系统里多了进程,本质是:操作系统内多了一套与进程相关的数据结构(task_struct)+进程的代码和数据(代码和数据就是比如上面的生成的mycode,它就是进程对应的代码和数据,但是fork后的子进程的代码和数据是什么?子进程默认情况会继承父进程的代码和数据结构)。

4. 常见疑问

  1. 系统多了个子进程,父进程在磁盘上有资源,但子并没有,且没有自己的代码和数据,那它是怎么执行的?

答:是因为子进程会继承父进程资源,执行父进程的代码。所以代码共享,且代码不可被修改,但如果代码中有写入内容,会发生写时拷贝。为了进程独立性。底层原理是:task_struct 会以父进程为模板,初始化子进程的task_struct。

  1. 假如父进程return了,会影响子进程吗?

答:不会,因为进程之间有独立性,且父进程已创建了子进程,父进程return完,子进程也会在执行。且父子进程返回的值,不一样,且会写入,但不会影响,因为有写时拷贝。

  1. fork之后父子谁先运行?

答:不确定,只要子进程创建出来,父进程和子进程谁先运行,是调度器会控制谁先运行。fork之后有两个执行流。

  1. 子进程为什么从fork函数调用之后开始执行?
    答:因为在fork之后,才会创建子进程。且父进程在磁盘等资源中有自己的一份。但子进程并没有。子进程必须只有继承父进程资源后,使用和父进程共享的代码和资源才可以执行。

实验wait()、waitpid()

  1. wait()基本使用:
      答:参数给NULL可得返回值是进程pid。如果没有wait到子进程则返回-1。
    如下代码:发现父进程可以回收子进程pid,子进程pid和父进程回收到的结果相等。
    请添加图片描述
    请添加图片描述
  2. wait()实现回收僵尸进程:
  • 前言:僵尸进程只能通过父进程wait()、waitpid()回收,kill -9 也不能杀死。
  • 代码:
    检查进程:while :; do ps ajx | head -1 && ps ajx | grep mycode| grep -v grep; sleep 1; echo "########"; done
    请添加图片描述
  • 效果:
    请添加图片描述
    请添加图片描述
  1. waitpid(),功能更加丰富
    请添加图片描述
  • 参数:
    id、退出码status、options、

waipid()基本使用和wait()一样。

  1. id= -1 可等待任意一个子进程。给特定id等待特定子进程。-1时等价于wait。
  2. status:这是个输出型参数,传入&status,内部操作的是*status,这样做完status上就带值了。可以输出观察进程退出的结果。
  • 代码:
    请添加图片描述
  1. 这里子进程用exit(0)退出,这里status退出码显示0,表示一切正常。
    请添加图片描述
  2. 如果exit(10),结果如下:返回status不是10,是2560。
    请添加图片描述
    请添加图片描述
  • 解释参数*status:
    首先,进程退出分三种情况:代码运行完结果正确、代码运行完结果不正确、代码异常终止。status有32位,只使用低16位。

请添加图片描述

  1. 程序运行完是否正确由进程退出码决定。main()的return和exit()决定退出码
  2. 代码异常终止必没运行完,且会收到异常信号。所以通过判断信号看是否是异常信号。
  3. status是退出码和信号。所以status使用的16位中的次低8位是进程退出状态。而低8位的前7位是进程退出时的退出状态,正常情况大部分是0,迪第8位是core_dump标志位。低7位是0,说明没有收到信号,是正常退出的。总之,先看次低8位的退出码,再看低8位信号
  4. 所以解析status:
    假设status = xxxxxxxx xxxxxxxx aaaaaaaa bbbbbbbb;其中高16位不使用,次低8位是进程退出码。可以使用:& 0x 0 0 0 0 F F 0 0 或 (>>8)&FF。
    低8位中低7位是退出信号,第8位是core dump标志位。可以使用:& 7F(7F有7位,7代表前3位111,F是后4位1111)。
  • 解析status代码:(子进程exit(10))
    请添加图片描述
    请添加图片描述
    子进程exit(10)是运行完毕,但收到异常退出码,所以在进程退出码上得到值。当运行出错异常终止,退出码就是0,只关注终止信号即可。

  • 常见waitpid的几种status返回情况:

  1. 运行完,且运行正常的退出情况:
    请添加图片描述
  2. 运行完,但是有异常,结果不正确,有退出码,这里用exit(11)模拟的,可调。
    请添加图片描述
  3. 未运行完遇到异常终止,会有信号值
    请添加图片描述
      通过kill - 2 命令提前杀死子进程,发现父进程的waitpid()的输出型参数status中退出码为0,信号值为2。所以异常终止时,退出码为0,关注信号值
    请添加图片描述
    请添加图片描述
    请添加图片描述
    总之,记忆:(>>8)&0XFF 和 &0x7F
  • 为什么bash中echo $?可以查看进程码?
      答:bash是命令行启动的所有进程的父进程。通过echo $?得到退出码是因为bash的本质也是通过waitpid()得到退出码。
    总之,退出码是运行完以后的返回,通过退出码可以看你运行结果是否正确
    总之,退出码是运行完以后的返回,通过退出码可以看你运行结果是否正确
    总之,退出码是运行完以后的返回,通过退出码可以看你运行结果是否正确
  • status其它获取退出码的方式:
    一切正常时:
    请添加图片描述请添加图片描述
  • 关于options:搭配子进程的pid_t类型的返回值去使用。
      答:调整阻塞和非阻塞方式的等待。
    用非阻塞方式,父进程的状态仍然是R。
    套在while(true)中使用,需要不断判断waitpid()的返回值。
    设置:
    请添加图片描述
    做判断的写法:
    请添加图片描述

【面试】
我听别人在面试,说自己做的项目,其实说涉及到的技术点或难点即可。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值