进程控制

  • 进程终止
    • 进程退出场景
    • 退出码
    • 错误码
    • 退出程序
      • exit
      • return
      • _exit
    • 总结
  • 进程等待
    • 进程等待必要性
    • 等待命令
      • wait
      • waitpid
    • 退出状态
    • 阻塞等待

进程终止

进程退出场景

我们常见的进程退出场景有如下几种:
代码运行完毕,结果正确
代码运行完毕,结果不正确
代码异常终止

退出码

我们可以通过echo $?来查看最近一次进程退出时的退出码。
这里使用一段代码来看看我们编写的函数的退出码是什么?

#include<stdio.h>int main()
{printf("hello world\n");return 1;
}

运行结果如下:

这里我们可以看到我们将return值设为1,使用echo $?打印出来的退出码也是1,说明main的return值就是进程的退出码。第二次打印退出码打印的是echo $?的退出码,这说明代码运行完毕,结果正确,返回0,代码运行完毕,结果不正确返回非0。

错误码

错误码和之前学过的命令行参数以及环境变量类似,都是以字符串的形式存放在对应是数组中,可以通过遍历下标来查看,下面通过一段代码来查看有哪些错误码

int main()
{int i=0;
for(i=0;i<100;i++)
{printf("%d:%s\n",i,strerror(i));
}
return 0;
}

运行结果如下:

退出程序

exit

使用exit命令可以直接退出程序,在任意位置调用,都代表终止进程,参数是退出码。

int main()
{printf("hello world\n");exit(10);printf("hello world\n");return 0;
}


这里看到exit后面()内的数字就是退出码,并且进程会在遇到exit位置时就会终止进程,不执行后面的代码。

return

return:main函数return,代表进程退出,return是我们比较常用的一种退出进程的方式,这里需要注意的是exit和return本身就会要求系统进行缓冲区刷新。执行return n等同于执行exit(n),因为调用main的运行时函数会将main的返回值当做 exit的参数。

int main()
{printf("hello world\n");exit(10);printf("hello world\n");return 0;
}


这里我们看到即使没有使用\n选项,系统也进行了缓冲区刷新。

_exit

_exit:强制终止进程,不进行程序的后续收尾工作,比如刷新缓冲区.

int main()
{printf("hello world");sleep(4);_exit(12);return 0;
}


这里我们可以看到使用_exit退出进程,他并不会进行刷新缓冲区,因此也看不到打印结果

总结

进程退出,在操作系统层面,做了什么?
系统层面少了一个进程,需要free PCB, free mm_struct ,free页表和各种映射关系,代码加数据和申请的空间也要被释放掉。

进程等待

进程等待必要性

  1. 之前我们了解到父子进程谁先执行并没有确定的情况,但是子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏,因此需要父进程等待子进程结束。
  2. 进程一旦变成僵尸状态,那就刀枪不入,kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。
  3. 我们需要知道父进程派给子进程的任务完成的如何。如子进程运行完成,结果对还是不对,或者是否正常退出。
  4. 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息

等待命令

wait

使用man手册我们可以查看wait指令的相关信息

wait命令成功返回被等待进程的pid失败则返回-1,他的参数是输出型参数用来获取子进程退出状态,不关心则设置为NULL。

int main()
{pid_t id=fork();if(id==0){//childint count=5;while(count){printf("if:%d child is running:count is %d \n",getpid(),count);count--;}exit(0);}//sleep(5);pid_t ret=wait(NULL);if(ret>0){printf("father wait success %d\n",ret);}else {printf("father wait failed\n");}return 0;
}

waitpid

还是使用man手册查看waitpid的介绍

waitpid的返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0; 如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
pid设置为-1时,表示等待任意一个子进程,与wait等效
当pid设置为大于0时,等待其进程ID与pid相等的子进程。

status退出状态:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)

option:
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。

int main()
{pid_t id=fork();if(id==0){//childint count=5;while(count){printf("id :%d child is running :count is %d\n",getpid(),count);count--;}exit(0);}pid_t ret=waitpid(id,NULL,0);if(ret>0){printf("father wait success :ret %d\n",ret);}else {printf("father wait failed\n");}return 0;
}

退出状态

使用wait和waitpid命令时,我们发现他都需要传入一个输出型参数,这个参数是进程状态,当我们不关心时可以输入NULL,但是如果我们想要获取进程状态呢?
父进程获得的status结果,一定和子进程退出情况强相关。status是一个整型,他有32个比特位,我们只看低16位。其中高8位接收的是进程的退出码,低7位接收的是进程的终止信号,第8个比特位表示信号core dump。

int main()
{pid_t id=fork();if(id==0){//childint count=5;while(count){printf("id :%d child is running :count is %d\n",getpid(),count);count--;}exit(10);}int status=0;pid_t ret=waitpid(id, &status ,0);if(ret>0){//正常退出printf("father wait success :ret %d\n",ret);printf("child exit code:%d\n",(status>>8)&0xFF);printf("child exit signal %d\n",(status)&0x7F);}else {printf("father wait failed\n");}return 0;
}

除此以外,还可以使用宏来获取对应的退出码:

int main()
{pid_t id=fork();if(id==0){//childint count=5;while(count){printf("id :%d child is running :count is %d\n",getpid(),count);count--;}sleep(5);exit(10);}int status=0;pid_t ret=waitpid(id, &status ,0);if(WIFEXITED(status)){//正常结束的,获取对应的退出码printf("exit code:%d\n",WEXITSTATUS(status));}if(ret>0){//正常退出printf("father wait success :ret %d\n",ret);printf("child exit code:%d\n",(status>>8)&0xFF);printf("child exit signal %d\n",(status)&0x7F);}else {printf("father wait failed\n");}return 0;
}


如果使用kill命令或者ctrl+c来终止进程,此时宏无法输出退出状态

bash是命令行启动的所有进程的父进程。
bash一定是通过wait方式得到子进程的退出结果,所以能看到进程的退出码。

阻塞等待

waitpid中的option选项:

  1. 0-阻塞等待,默认行为
  2. WNOHANG:设置等待方式为非阻塞等待

阻塞等待:需要等一个进程结束,一直等待
非阻塞等待:需要进行基于非阻塞等待的轮询方案。
阻塞的本质是将进程的PCB被放入了等待队列,并将进程的状态改为S状态
返回的本质是将进程的PCB从等待队列拿到运行队列中,从而被CPU调度

int main()
{pid_t id=fork();if(id==0){//childint count=5;while(count){printf("child is running id : %d\n",getpid());count--;sleep(1);}sleep(5);exit(1);}int status=0;pid_t ret = waitpid(id,&status,WNOHANG);while(ret==0){ret =  waitpid(id,&status,WNOHANG);if(ret==0){//子进程没有退出,但是等待成功需要重复等待printf("waiting  ret: %d status :%d\n",ret,(status>>8)&0xFF);sleep(1);}else if(ret>0){//子进程退出了waitpid也成功了,获得相应的结果printf("wait success ret: %d status: %d\n",ret,(status>>8)&0xFF);}else {//等待失败}}return 0;
}

进程控制—终止和等待相关推荐

  1. Linux 进程控制(创建/退出/等待/替换)

    目录 进程创建 fork()函数 fork返回值 fork写时拷贝 fork失败原因 fork用法 进程退出 退出场景 常见的退出方法 正常退出 异常退出 _exit()系统调用 exit()函数 _ ...

  2. 【Linux】进程控制2-进程等待

    文章目录 进程等待 进程等待的必要性 wait函数 waitpid函数 进程等待 进程等待的必要性 我们之前提到过僵尸进程,僵尸进程就是子进程先于父进程退出,子进程的退出状态信息发送给父进程但是父进程 ...

  3. Linux_进程控制(创建进程,等待进程,进程终止)

    文章目录 1.创建进程 1.1 fork()函数初识 1.2 fork()创建进程代码示例 2.等待进程 2.1 进程等待概念 2.2进程等待必要性 2.3 进程等待方法 2.3.1 wait 2.3 ...

  4. 【Linux】进程控制(进程创建、进程终止、进程等待、进程替换)

    文章目录 一.进程创建 1.1 系统调用 fork 1.2 理解 fork 的返回值 1.3 写时拷贝策略 二.进程终止 2.1 main 函数的返回值 2.2 进程退出的几种情况 2.3 进程退出码 ...

  5. 进程控制(进程创建与终止 | 进程等待 | 程序替换)

    文章目录 一.进程创建 1. fork函数 2. fork创建进程 3. 写时拷贝 二.进程终止 1. 进程退出有三种情况 2. 常见进程终止方法 三.进程等待 背景(必要性) 1. 进程等待的方法 ...

  6. Linux 进程控制 :进程创建,进程终止,进程等待,程序替换

    进程创建 进程终止 进程等待 程序替换 进程创建 fork函数 创建一个子进程,父子进程代码共享,数据独有 #include <unistd.h> pid_t fork(void); 返回 ...

  7. Linux C编程--进程介绍3--进程终止和等待

    进程结束 1.在Linux中任何让一个进程结束 进程退出表示进程即将结束.在Linux中进程退出分为了正常退出和异常退出两种. 1>正常退出 a. 在main()函数中执行return . b. ...

  8. 模拟进程创建、终止、阻塞、唤醒原语_操作系统基础8-进程及进程控制

    进程(Process) 的定义 从不同的角度,进程可以有不同的定义,传统典型的定义: 进程是程序的一次执行过程. 或者:一个正在执行的程序的实例 进程是一个程序及其数据在处理机上顺序执行所发生的活动 ...

  9. 进程控制:进程的创建、终止、阻塞、唤醒和切换

    进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程.撤销已有进程.实现进程状态转换等功能.在操作系统中,一般把进程控制用的程序段称为原语,原语的特点是执行期间不允许中断,它是一个不 ...

最新文章

  1. 2021-2027年中国手机天线行业竞争格局分析及发展趋势预测报告
  2. JMeter学习-017-java.net.SocketException: Permission denied: connect 解决方案
  3. java注释模板_Java注释模板设置
  4. python sort 多级排序_Python使用sort和class实现的多级排序功能示例
  5. [项目经验]玩转开源项目
  6. Effective_STL 学习笔记(三) 使容器里对象的拷贝操作轻量而正确
  7. [转]Ubuntu下快速安装python
  8. Java泛型原理、类型擦除
  9. wpsoffice 安装包_WPS office (安卓、ios) 企业版 软件介绍(附安装包)
  10. 毕业设计 基于java的贴吧论坛_java毕业设计_springboot框架的论坛贴吧
  11. 个人笔记本安装ubuntu系统
  12. 小孔子内容管理系统V2.0测试
  13. 人脸识别考勤机选型验收标准
  14. java ftp 卡死_ftpclient卡死问题
  15. (附源码)springboot教材订购系统 毕业设计 081419
  16. 浅析Marshmallow在flask中的应用
  17. 使用html2canvas生成海报
  18. Origin Pro 8.5 导出EPS格式稿件图片的设置
  19. 电脑弹窗消息=springboot瘦包+PC消息提醒
  20. RKISP_Driver_User_Manual

热门文章

  1. “梗文化”盛产2000w+播放,快手主播又多一个出圈技能?
  2. 1080 Graduate Admission (30 分)
  3. Spring Boot Vue Element入门实战(完结)
  4. 老程序员:这是我见过最牛的代码,切勿模仿
  5. python用openpyxl包操作xlsx文件,统计表中合作电影数目最多的两个演员
  6. Auto.js脚本程序打包
  7. c语言二级指针实现队列,C语言二级指针底层实现
  8. python r语言 结合 部署_Win10 下安装R,rpy2,Rstudio 安装与配置 并实现Python 调用 R语言...
  9. python3识别图中的文字_Python3.x:如何识别图片上的文字
  10. Project Structure