进程控制—终止和等待
进程控制
- 进程终止
- 进程退出场景
- 退出码
- 错误码
- 退出程序
- 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页表和各种映射关系,代码加数据和申请的空间也要被释放掉。
进程等待
进程等待必要性
- 之前我们了解到父子进程谁先执行并没有确定的情况,但是子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏,因此需要父进程等待子进程结束。
- 进程一旦变成僵尸状态,那就刀枪不入,kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。
- 我们需要知道父进程派给子进程的任务完成的如何。如子进程运行完成,结果对还是不对,或者是否正常退出。
- 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息
等待命令
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选项:
- 0-阻塞等待,默认行为
- 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;
}
进程控制—终止和等待相关推荐
- Linux 进程控制(创建/退出/等待/替换)
目录 进程创建 fork()函数 fork返回值 fork写时拷贝 fork失败原因 fork用法 进程退出 退出场景 常见的退出方法 正常退出 异常退出 _exit()系统调用 exit()函数 _ ...
- 【Linux】进程控制2-进程等待
文章目录 进程等待 进程等待的必要性 wait函数 waitpid函数 进程等待 进程等待的必要性 我们之前提到过僵尸进程,僵尸进程就是子进程先于父进程退出,子进程的退出状态信息发送给父进程但是父进程 ...
- Linux_进程控制(创建进程,等待进程,进程终止)
文章目录 1.创建进程 1.1 fork()函数初识 1.2 fork()创建进程代码示例 2.等待进程 2.1 进程等待概念 2.2进程等待必要性 2.3 进程等待方法 2.3.1 wait 2.3 ...
- 【Linux】进程控制(进程创建、进程终止、进程等待、进程替换)
文章目录 一.进程创建 1.1 系统调用 fork 1.2 理解 fork 的返回值 1.3 写时拷贝策略 二.进程终止 2.1 main 函数的返回值 2.2 进程退出的几种情况 2.3 进程退出码 ...
- 进程控制(进程创建与终止 | 进程等待 | 程序替换)
文章目录 一.进程创建 1. fork函数 2. fork创建进程 3. 写时拷贝 二.进程终止 1. 进程退出有三种情况 2. 常见进程终止方法 三.进程等待 背景(必要性) 1. 进程等待的方法 ...
- Linux 进程控制 :进程创建,进程终止,进程等待,程序替换
进程创建 进程终止 进程等待 程序替换 进程创建 fork函数 创建一个子进程,父子进程代码共享,数据独有 #include <unistd.h> pid_t fork(void); 返回 ...
- Linux C编程--进程介绍3--进程终止和等待
进程结束 1.在Linux中任何让一个进程结束 进程退出表示进程即将结束.在Linux中进程退出分为了正常退出和异常退出两种. 1>正常退出 a. 在main()函数中执行return . b. ...
- 模拟进程创建、终止、阻塞、唤醒原语_操作系统基础8-进程及进程控制
进程(Process) 的定义 从不同的角度,进程可以有不同的定义,传统典型的定义: 进程是程序的一次执行过程. 或者:一个正在执行的程序的实例 进程是一个程序及其数据在处理机上顺序执行所发生的活动 ...
- 进程控制:进程的创建、终止、阻塞、唤醒和切换
进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程.撤销已有进程.实现进程状态转换等功能.在操作系统中,一般把进程控制用的程序段称为原语,原语的特点是执行期间不允许中断,它是一个不 ...
最新文章
- 2021-2027年中国手机天线行业竞争格局分析及发展趋势预测报告
- JMeter学习-017-java.net.SocketException: Permission denied: connect 解决方案
- java注释模板_Java注释模板设置
- python sort 多级排序_Python使用sort和class实现的多级排序功能示例
- [项目经验]玩转开源项目
- Effective_STL 学习笔记(三) 使容器里对象的拷贝操作轻量而正确
- [转]Ubuntu下快速安装python
- Java泛型原理、类型擦除
- wpsoffice 安装包_WPS office (安卓、ios) 企业版 软件介绍(附安装包)
- 毕业设计 基于java的贴吧论坛_java毕业设计_springboot框架的论坛贴吧
- 个人笔记本安装ubuntu系统
- 小孔子内容管理系统V2.0测试
- 人脸识别考勤机选型验收标准
- java ftp 卡死_ftpclient卡死问题
- (附源码)springboot教材订购系统 毕业设计 081419
- 浅析Marshmallow在flask中的应用
- 使用html2canvas生成海报
- Origin Pro 8.5 导出EPS格式稿件图片的设置
- 电脑弹窗消息=springboot瘦包+PC消息提醒
- RKISP_Driver_User_Manual
热门文章
- “梗文化”盛产2000w+播放,快手主播又多一个出圈技能?
- 1080 Graduate Admission (30 分)
- Spring Boot Vue Element入门实战(完结)
- 老程序员:这是我见过最牛的代码,切勿模仿
- python用openpyxl包操作xlsx文件,统计表中合作电影数目最多的两个演员
- Auto.js脚本程序打包
- c语言二级指针实现队列,C语言二级指针底层实现
- python r语言 结合 部署_Win10 下安装R,rpy2,Rstudio 安装与配置 并实现Python 调用 R语言...
- python3识别图中的文字_Python3.x:如何识别图片上的文字
- Project Structure