fork():创建子进程,并返回进程id。

wait(&status):等待子进程终止。如果成功则会返回僵尸子进程的pid,status的值会是子进程的exitcode。

exit(value):进程正常退出,并返回退出值value

prctl(PR_SET_CHILD_SUBREAPER):设置当前进程为subreaper进程。

零、示例代码即可能的输出结果

目录

一、fork()

二、wait()

三、subreaper

四、解读上述代码和输出结果


#include <stdio.h>
#include <unistd.h>
#include <wait.h>
#include <sys/prctl.h>
int main(){int pid ,r,status ;printf("mark process %d as a subreaper\n",getpid());r=prctl(PR_SET_CHILD_SUBREAPER);pid = fork();if(pid){//parent printf("subreaper %d child =%d\n",getpid(),pid);while(1){pid =wait(&status);if(pid >0){printf("subreaper %d wait a ZOMBIE=%d\n",getpid(),pid);}else{break;}}}else{//childprintf("child %d parent=%d\n",getpid(),(pid_t)getppid());pid=fork();if(pid){printf("child%d start : grandchild=%d\n",getpid(),pid);printf("child%d exit : grandchild=%d\n",getpid(),pid);}else{printf("grandchild%d start : myparent=%d\n",getpid(),getppid());printf("grandchild%d end : myparent=%d\n",getpid(),getppid());}}}

运行结果:(每次运行可能顺序不一样)

在Linux 中,每个用户在同一时间只能有一定数量的进程。用户资源限制文件通常在/etc/security/limits.conf 文件中设置。进程有两种执行状态,一种是内核态,一种是用户态。每个进程都在内核中下产生并开始执行,想调用硬件设备例如操作CPU,键盘,或者想执行系统调用都是在内核态下完成的。修改状态寄存器的值就可以从内核态转化为用户态。一旦转为用户态,那么就无法直接访问硬件相关的设备,想要重新转为内核态只有3种方式:硬件中断,异常,系统调用。 可以说,内核是操作系统之下的部分,用户是操作系统之上的部分。用户只需关心操作系统为用户提供了哪些可访问内核的接口就行。

在内核模式中,每个进程都有完全相同的代码段,数据段和堆,但是每个进程都有只属于自己的栈。

一、fork()

创建子进程并返回子进程的pid , int pid = fork();   如果fork失败则为-1。当创建了子进程后,子进程和父进程在用户态的映像完全相同,但是在内核态下的映像只有栈有区别,意味着子进程和父进程有相同的代码和数据。因为创建子进程时用户态的栈也是一样的,意味着栈帧情况也是一样的。创建完后子进程和父进程都从fork()后继续执行.fork()方法调用了内核中kfork()函数,它对创建出来的子进程返回是0,父进程返回值是子进程的进程号;

int pid =fork();
if(pid=-1){//父进程创建子进程失败的分支
}else if(pid ==0){//子进程执行的分支,因为子进程返回的pid是0
}else {//父进程执行的分支,pid是子进程的id
}

二、wait()

等待僵尸子进程。所谓的僵尸进程,就是程序已经结束但是资源未释放的进程。wait除了返回僵尸子进程的id,获取子进程的退出状态,还会释放僵尸子进程。wait系统调用将调用内核中的kwait函数

三、subreaper

进程可以用系统调用定义自己为subreaper进程:

prctl(PR_SET_CHILD_SUBREAPER);

如果子进程的父进程先死亡,那么该子进程就会成为一个孤儿进程。在Linux中,标记为subreaper的祖先进程会成为该孤儿的父进程,否则将成为P1进程子进程。(P1进程是操作系统初始化的进程,除P0和P1进程,其他所有进程都是P1进程的子孙进程)。不过要注意的是,当P1清理重定父级进程时,会丢失关于子进程的所有信息。P1因为进程等级高,当P1作为孤儿进程的父进程时服务管理器不能再从服务守护进程中接收SIGCHLD信号,也不能等待任何僵尸子进程。定义subreaper就可以很好的解决上述问题,并且可以有效地减少P1进程的工作量。

显示当前用户的subreaper 进程的PID 和信息:

ps fxau | grep USERNAME | grep "/sbin/upstart"

四、解读上述代码和输出结果

就运行结果而言,

1)当fork创建出来子进程后,父进程获取到CPU使用权先执行,并打印出了

然后进入while循环等待子进程执行结束。

2)接下来子进程执行并打印出了,

之后子进程 fork 创建出了一个子进程的子进程即孙子进程。

3)子进程先执行完毕,并打印出:

此时,子进程执行完毕但是未释放进程资源,于是成为了僵尸进程。

4)此时父进程获取到CPU使用权,通过wait返回子进程的pid,继续执行打印出了

wait释放了子进程的资源,使孙子进程成为了孤儿进程,但是由于之前父进程(pid=3434)将自己设置成了PR_SET_CHILD_SUBREAPER  , 使 孙子进程(pid=3436)的父亲不再是已经死亡的(pid=3435),而是父进程(pid=3434)。

5)所以当孙子执行完自己的代码后,打印出

成为了僵尸进程后,被父进程 wait() 释放出来,打印出

后结束。

Linux C :系统调用-fork,wait,subreaper相关推荐

  1. linux内核-系统调用fork、vfork与clone

    前面已经简要地介绍过fork与clone二者的作用于区别.这里先来看一下二者在程序设计接口上的不同: pid_t fork(void); int clone(int (*fn)(void *), vo ...

  2. linux内核-系统调用execve()

    读者在linux内核-系统调用fork.vfork与clone中已经看到,进程通常是按其父进程的原样复制出来的,在多数情况下,如果复制出来的子进程不能与父进程分道扬镳,走自己的路,那就没多大意义.所以 ...

  3. linux fork 用法,Linux系统调用fork()用法详解

    linux 系统调用fork()的用法详解 Linux系统调用fork()用法详解 1. 先看下面代码: #include #include //pid_t类型定义 #include //函数fork ...

  4. OS / Linux / clone、fork、vfork 与 pthread_create 创建线程有何不同

    进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合,这些资源在Linux中被抽象成各种数据对象:进程控制块.虚存空间.文件系统,文件I/O.信号处理函数.所以创建一个进程的过程就是这些数 ...

  5. linux shell中fork、source、exec的区别

    exec和source都属于bash内部命令(builtins commands),在bash下输入man exec或man source可以查看所有的内部命令信息. bash shell的命令分为两 ...

  6. linux系统列表,Linux常用系统调用列表-20210415054405.docx-原创力文档

    Linux Linux常用系统调用列表作者:雷震 2002年3月 本文列出了大部分常见的Linux系统调用,并附有简要中文说明. 以下是Linux系统调用的一个列表,包含了大部分常用系统调用和由系统调 ...

  7. Linux的系统调用、网络连接状态、磁盘I/O;可疑行为监控/日志收集、SHELL命令执行流程

    http://man7.org/linux/man-pages/man7/capabilities.7.html http://www.cnblogs.com/LittleHann/p/3850653 ...

  8. Linux 0.11 fork 函数(二)

    Linux 0.11 系列文章 Linux 0.11启动过程分析(一) Linux 0.11 fork 函数(二) Linux0.11 缺页处理(三) Linux0.11 根文件系统挂载(四) Lin ...

  9. Unix/Linux编程:fork()进程详解

    文章目录 理论 进程 fork,wait,exec fork 实践 验证 `fork函数被调用一次但返回两次` 子进程和父进程之间不共享数据空间 父子进程间的文件共享 fork的内存语义 同步信号以规 ...

最新文章

  1. leetcode算法题--对链表进行插入排序
  2. Linux 系统应用编程——网络编程(服务器模型)
  3. 单用户修改root密码--centos6.2
  4. 虚拟机从网卡路由问题
  5. c语言中srand的作用,C语言中srand(), rand(), time()函数  转载
  6. 怎么改路由器的密码?
  7. ajax 在php中一个运用
  8. SQL的几种连接查询方式(内连接、外连接、全连接、联合查询)
  9. 2021年01月18号学习产品经理之电商项目从0-1
  10. 空间点到空间直线的距离求解
  11. NLP论文阅读1--More Data, More Relations, More Context and More Openness: A Review and Outlook for Relati
  12. Unity-ShaderLab 逆向还原《原神》角色卡通渲染思路与实现(保姆级教学)-1
  13. ADS,AXD基本使用说明
  14. 加拿大渥太华民众寒冬享受运河滑冰道乐趣
  15. 联想y7000笔记如何安装matlab,联想y7000p安装配置ubuntu笔记
  16. 计算机动画题目,3DMax2014计算机动画作业练习题
  17. 第二章 02 天牛质感
  18. 用c语言实现基本数据结构(哈希表)
  19. 去法国,买哪些伴手礼既有面子又不破费
  20. Java8新特性1:lambda表达式入门--由浅入深,从单发步枪迈向自动步枪

热门文章

  1. linux下file命令使用技巧
  2. 教您快速解决MindManager15安装中的.NET难题
  3. xutils,afinal的数据库升级要注意的地方
  4. Enterprise Vault 10.0.4 FOR Exchange2013 部署之二 -安装过程
  5. 【python自动化办公04】word操作-word文字颜色修改
  6. VOC 灰度图 索引图
  7. JAVA8 Optional新特性和使用详解
  8. spring boot 整合redis实现方法缓存
  9. reactjs css modules解决组件间样式覆盖问题
  10. linux配置chrony时间同步