一、进程等待
1.进程等待的作用
在一个程序中,如果父进程创建子进程后,子进程先于父进程退出,父进程如果什么都不做,就会产生僵尸进程的问题,对于这种情况,父进程此时就需要等待子进程退出,回收子进程资源,接收子进程的退出返回值,避免产生僵尸进程。
2.如何实现进程等待
阻塞接口:为了完成一个功能发起一个调用,但调用完成条件不具备,则接口一直等待不返回
非阻塞接口:为了完成一个功能发起一个调用,但调用完成条件不具备,则立即报错返回
(1) wait()函数 (阻塞接口)
函数原型: pid_t wait(int*status);
函数头文件:#include<sys/types.h>
#include<sys/wait.h>
返回值:成功则返回进程的pid,失败则返回-1
参数status:获取进程退出状态,不关心可以设置为NULL
注:wait()函数返回值并不是status,它返回的是进程pid,而status是进程退出的状态,被保存在其低16位中的高8位,status不能简单的当作整形来看待,可以当作位图来看待,具体如下:(只研究status低16位)
core dump标志位默认为0
如果进程正常退出,则 低6位异常值为0,返回的数据就是低16位代表的十进制数
如果进程异常退出,则低6位不为0,返回的数据也是低16位代表的十进制数
在进程退出的时候,我们通常会用exit()函数,exit(a)函数中的参数a就为status的退出状态,但是此数不能过大,因为status 的退出状态只接受一个字节(8位),超出的数位就会被截断
具体实现:
运行结果:
(2) waitpid()函数
对于wait()函数来说,其只能进行阻塞等待,就是将父进程先阻塞,知道父进程接收到子进程的退出返回值,父进程才开始继续往下执行,资料利用率低。此时就有一种新的等待函数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:
设置为WNOHANG,表示此时为非阻塞等待,若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该 子进程的ID。
具体实现:
运行结果:
二、进程替换
1.替换原理:
替换一个进程正在调度管理的程序
用
fork
创建子进程后执行的是和父进程相同的程序
(
但有可能执行不同的代码分支
),
子进程往往要调用一种
exec
函数 以执行另一个程序。
当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
2.替换函数
int execve(const char *path, char *const argv[], char *const envp[]);
功能:将path 这个路径名所指定的程序加载到内存中,然后让当前程序调度管理这个程序的运行
argv:用于设定这个程序的的运行参数
envp:用于设定这个程序的环境变量
返回值:替换成功没有返回值,因为替换成功就运行其他程序了
替换失败返回 -1
注:execve()中,path需要自己指定,envp也需要自己指定 execve("./bin/ls",argv,env)
int execvp(const char *file, char *const argv[]);
与上述execve相类似,第一个参数path不需要指定路径,默认会在PATH环境变量指定的路径下去找
int execv(const char *path, char *const argv[]);
第一个参数需要自己设定,但不需要设定环境变量 execve("./bin/ls",argv)
当
argv[]={"ls","-a","-l","NULL}
int execl(const char *path, const char *arg, ...);
第一个参数需要自己设定路径,不需要自己设置环境变量,第二个参数argv为不定参数
execl("./bin/ls","ls","-l","-a",NULL);
int execlp(const char *file, const char *arg, ...);
第一个参数不需要自己设定路径,不需要自己设置环境变量,第二个参数argv为不定参数
execlp("ls","ls","-l","-a",NULL);
int execle(const char *path, const char *arg, ...,char *const envp[]);
第一个参数需要自己设定路径,需要自己设置环境变量,第二个参数argv为不定参数
execlp("./bin/ls","ls","-l","-a",NULL,env);
具体实现:
运行结果: