目录
1. exec 族函数
1.1 exec 族函数的作用
我们用 fork 函数创建新进程后,经常会在新进程中调用 exec 函数去执行另外一个程序。当进程调用 exec 函数时,该进程被完全替换为新程序。因为调用 exec 函数并不创建新进程,所以前后进程的ID并没有改变。
1.2 函数族:
exec 函数族分别是:execl, execlp, execle, execv, execvp, execvpe
- 带 p 的一类 exec 函数,包括 execlp、execvp、execvpe,如果参数 file 中包含 /,则就将其视为路径名,否则就按 PATH 环境变量,在它所指定的各目录中搜寻可执行文件。
- 带 l 的一类 exec 函数(l表示list,包括 execl、execlp、execle,要求将新程序的每个命令行参数都说明为一个单独的参数。这种参数表以空指针结尾。
1.3 返回值:
exec 函数族的函数执行成功后不会返回,调用失败时,会设置 errno 并返回-1,然后从原程序的调用点接着往下执行。
1.4 参数说明:
path:可执行文件的路径名字
arg: 可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且 arg 必须以 NULL 结束
file: 如果参数 file 中包含 /,则就将其视为路径名,否则就按 PATH 环境变量,在它所指定的各目录中搜寻可执行文件。
1.5 excelp 代码实例
代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
printf("before execlp\n");
if (execlp("ps", "ps", "-l", NULL) == -1)
{
printf("execlp failed!\n");
perror("execlp");
}
printf("after execlp\n"); // 调用 execlp 函数后就不打印这句了
return 0;
}
运行结果:
执行程序与在终端直接输入 ps -l 的效果一样,且调用 execlp 后,后续没走完的程序将不再继续生效,该进程被完全替换为新程序。
2. 孤儿进程和僵尸进程
2.1 孤儿进程
父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程。 Linux 避免系统存在过多孤儿进程,init(进程号为1)进程收留孤儿进程,变成孤儿进程的父进程。
2.2 僵尸进程
一个比较特殊的状态,当子进程退出时,父进程(使用wait()系统调用)没有读取到子进程退出的返回代码时就会产生僵尸进程。僵尸进程会在以终止状态保持在进程表中,并且会一直等待父进程读取退出状态代码。
3. 进程回收
3.1 wait 阻塞函数
函数作用:
- 1.阻塞并等待子进程退出
- 2.回收子进程残留资源
- 3.获取子进程结束状态(退出原因)
pid_t wait(int *wstatus);
返回值:
‐1 : 回收失败,已经没有子进程了
>0 : 回收子进程对应的 pid
参数 :
status 判断子进程如何退出状态
1.WIFEXITED(status):为非0 ,进程正常结束
WEXITSTATUS(status)
如上宏为真,使用此宏,获取进程退出状态的参数
2.WIFSIGNALED(status):为非0,进程异常退出
WTERMSIG(status):
如上宏为真,使用此宏,取得使进程种植的那个信号的编号
调用一次只能回收一个子进程
3.2 waitpid 函数
函数作用:同wait函数
pid_t waitpid(pid_t pid, int *status, int options);
参数
1.pid: 指定回收某个子进程
pid == ‐1 回收所有子进程
while((wpid = waitpid(‐1,status,0)) != ‐1)
pid > 0 回收某个 pid 相等的子进程
pid == 0 回收当前进程组的任一子进程
pid < 0 子进程的 pid 取反(加减号)
2.status: 子进程的退出状态,用法同 wait 函数
3.options:设置为 WNOHANG,函数非阻塞,设置为0,函数阻塞
返回值:
>0 :返回清理掉的子进程ID
‐1 :回收失败,无子进程
如果为非阻塞
=0 :参数3为 WNOHANG,且子进程正在运行
4 进程退出
4.1 正常退出
- 1. main 函数调用 return
- 2. 进程调用 exit(), 标准 C 库
- 3. 进程调用 _exit() 或者 _Exit(), 属于系统调用
4.2 异常退出
- 1.调用 abort 函数
- 2.当进程收到某些信号时,比如 ctrl +C
- 3.最后一个线程对取消(cancellation)请求做出相应
对上述任一一种终止情形,我们都希望终止进程能够通知其父进程它是如何终止的。对于三个终止函数(exit, _exit和 _ Exit),实现这一点的方法是,将其退出状态(exit status)作为参数传送给函数,在异常终止情况下,内核(不是进程本身)产生一个指示其异常终止原因的终止状态(termination status)。在任意一种情况下,该终止进程的父进程都能用 wait 或 waitpid 函数取得终止状态。