Linux进程控制(进程退出+进程等待)
创始人
2024-05-13 05:50:48
0

目录

一、子进程创建

1.1 fork函数深入

1.2 写时拷贝

二、进程退出

2.1.1 进程退出码概念

2.1.2 系统退出码文字描述

 2.1.3 _exit和exit函数

2.1.4 查看退出码

三、进程等待

3.1 进程等待解决僵尸进程

3.2 进程等待方法

3.2.1 wait

 3.2.2 waitpid()

 四、阻塞与非阻塞等待

4.1 阻塞等待

4.2 非阻塞等待

4.3 多次非阻塞等待(轮询) 

 4.4 非阻塞等待好处


一、子进程创建

1.1 fork函数深入

fork初识在我另一篇博客:fork初识

当调用fork函数以后,OS会给子进程:

①.分配新的内存块和内核数据结构给子进程
②.将父进程部分数据结构内容拷贝至子进程
③.添加子进程到系统进程列表当中
④.fork返回,开始调度器调度

如何理解父子进程fork函数返回值不同?

1.为什么有两个返回值?

当一个函数返回的时候说明函数任务已经完成,当fork返回之前,子进程已经被创建好了,子进程会拷贝父进程代码和部分数据,两次返回其实就是父子进程都有了fork函数,所以return会分流

2.为什么父子进程返回值不同?

父子进程的对应关系时1:n ,相同的代码,返回值不同,这样就可以让父子进程完成父子进程的对应代码(确定自己的身份)

1.2 写时拷贝

子进程创建会拷贝父进程代码和部分数据,它们会共享部分数据!但是如果父或子进程想修改数据,操作系统会进行写实拷贝!它会拷贝数据在另一块内存空间存储!


二、进程退出

2.1.1 进程退出码概念

main函数return值是退出码,退出码的作用时让我们判断进程任务是否成功完成!当退出码为0时,进程任务完成,当退出码为!0,进程任务没有完成!

2.1.2 系统退出码文字描述


图一


图二


 2.1.3 _exit和exit函数

代码跑完后用return返回退出码,代码没跑完也可以直接返回退出码终止程序!

我们可以调用exit(C库函数) 或者_exit(系统调用) ! 两者区别是前者会在退出前刷新缓冲区,后者不会!



 具体用法:

#include 
#include int main ()
{printf("程序的开头....\n");printf("退出程序....\n");exit(0);//==_exit(0);printf("程序的结尾....\n");return(0);
}


2.1.4 查看退出码

利用echo 可以获取上一个进程的退出码!


三、进程等待

3.1 进程等待解决僵尸进程

前面我们提到僵尸进程,子进程等待父进程回收自己的资源与退出信息,如果父进程一直不获取子进程退出信息,子进程就会进入僵尸状态,僵尸进程无法被手动杀死!从而造成内存泄漏!我们利用进程等待方式解决僵尸进程!

3.2 进程等待方法


3.2.1 wait

返回值:
成功返回被等待进程pid,失败返回-1。
参数:
输出型参数,获取子进程退出状态,不关心则可以设置成为NULL

下面我们来看看代码效果:

#include 
#include
#include
#include
#include
int main()
{pid_t id=fork();if(id==0){int cnt=5;while(1){printf("我是子进程,我的id=%d,父进程id=%d,cnt=%d\n",getpid(),getppid(),cnt);sleep(1);cnt--;if(cnt==0){exit(0);//进程退出}}}else{sleep(10);pid_t ret=wait(NULL);//回收sleep(3);printf("wait success:%d\n",ret);//打印回收结果}return 0;
}

 


 3.2.2 waitpid()

pid_ t waitpid(pid_t pid, int *status, int options);

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

status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。


获取进程的status
wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充
如果传递NULL,表示不关心子进程的退出状态信息。
否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程
status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位)

位图:

信号码:


正常退出:

#include 
#include
#include
#include
#include
int main()
{pid_t id=fork();if(id==0){int cnt=5;while(1){printf("我是子进程,我的id=%d,父进程id=%d,cnt=%d\n",getpid(),getppid(),cnt);sleep(1);cnt--;if(cnt==0){exit(10);//进程退出}}}int status=0;//进程退出状态,以位图存储信息pid_t ret=waitpid(id,&status,0);if(id>0){printf("wait success:%d   sig code=%d    child exit code=%d\n",ret,status&0X7F,(status>>8)&0xFF);}return 0;
}


信号杀死野指针:

#include 
#include
#include
#include
#include
int main()
{pid_t id=fork();if(id==0){int cnt=5;while(1){printf("我是子进程,我的id=%d,父进程id=%d,cnt=%d\n",getpid(),getppid(),cnt);sleep(1);cnt--;//野指针!int *a=NULL;*a=100;if(cnt==0){exit(10);//进程退出}}}int status=0;//进程退出状态,以位图存储信息pid_t ret=waitpid(id,&status,0);if(id>0){printf("wait success:%d   sig code=%d    child exit code=%d\n",ret,status&0X7F,(status>>8)&0xFF);}return 0;
}


 四、阻塞与非阻塞等待

4.1 阻塞等待

阻塞等待指的时wait/waitpid会一直等到子进程进程退出,然后拿到结果!上面我们写的代码都是阻塞等待,子进程不退出,我们的函数就拿不到结果!

4.2 非阻塞等待

不管子进程有没有结束,waitpid都会立刻返回结果!

子进程退出了,返回值>0;

子进程没退出,返回值=0;

出错返回值=-1;

#include 
#include
#include
#include
#include
int main()
{pid_t id=fork();if(id==0){int cnt=5;while(1){printf("我是子进程,我的id=%d,父进程id=%d,cnt=%d\n",getpid(),getppid(),cnt--);sleep(1);if(cnt==0){exit(10);//进程退出}}}int status=0;//进程退出状态,以位图存储信息pid_t ret=waitpid(id,&status,WNOHANG);//以非阻塞等待if(ret>0){printf("wait success:%d   sig code=%d    child exit code=%d\n",ret,status&0X7F,(status>>8)&0xFF);}else if(ret==0){printf("wait success child process is running....\n");sleep(5);//拿到结果后睡眠,让子进程先退出}else{printf("wait error...\n");}return 0;
}


4.3 多次非阻塞等待(轮询) 

轮询:父进程一直监测子进程退出结果,如果子进程没退出,父进程依然可以执行自己的代码!如果退出,父进程获取子进程退出结果!

#include 
#include
#include
#include
#include
int main()
{pid_t id=fork();if(id==0){int cnt=5;while(1){printf("我是子进程,我的id=%d,父进程id=%d,cnt=%d\n",getpid(),getppid(),cnt--);sleep(1);if(cnt==0){exit(10);//进程退出}}}while(1){int status=0;//进程退出状态,以位图存储信息pid_t ret=waitpid(id,&status,WNOHANG);if(ret>0)//子进程退出{printf("wait success:%d   sig code=%d    child exit code=%d\n",ret,status&0X7F,(status>>8)&0xFF);break;}else if(ret==0)//子进程没退出{//父进程做自己的工作printf("wait success child process is running....\n");sleep(1);}else//出错{printf("wait error...\n");break;}}return 0;
}


 4.4 非阻塞等待好处

非阻塞等待不会让父进程一直等待到子进程退出,不会占用父进程所有精力,父进程可以在轮询期间完成自己的任务!


相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...