Linux进程等待进程终止与程序替换

2019-07-14 12:11发布

进程等待

  • 概念:进程等待就是子进程的状态改变
  • 作用:避免产生僵尸进程。一个进程在终止时会关闭所有的文件描述符,释放分配在用户空间的内存,但退出原因还保存在PCB中,如果该进程是正常终止,那么它的退出状态就会保存在PCB中,若果该进程不是正常终止,则会将导致进程异常终止的信号保存在PCB中。那么父进程便可以通过调用wait()函数或者waitpid()函数来查看子进程退出信息,然后可以彻底清除掉子进程。
  • 用法: wait()函数 waitpid()函数
wait()函数
  • 作用:父进程调用wait()函数获取子进程退出信息,回收子进程的残留资源
  • 函数功能
    阻塞等待子进程退出
    回收子进程残留资源
    获取子进程退出状态
  • 函数原型 pid_t wait(int* status) 阻塞函数
    调用成功返回被清理掉的子进程的进程ID,失败则返回-1
阻塞:为了完成某功能而发起函数调用,若当前不具备完成条件,则一直等待,直到具备完成条件才返回。反之,若不具有完成条件则立即返回就是非阻塞 waitpid()函数
  • 作用:与wait()函数一样可以回收子进程的资源,但相比wait()函数它更加灵活,它可以指定子进程回收,也可以设置函数位非阻塞态。
  • 函数原型 pid_t waitpid(pid_t pid , int * status ,int options) 默认位阻塞函数
    参数: pid == -1 与wait()函数一样,等待任意一个子进程;pid > 0 回收指定ID的子进程
    options: 可设置函数为非阻塞,WNOHANG,若子进程没有结束,则函数返回0,不等待。若正常,则返回子进程的pid
status
  • status:通过status可以获取子进程的退出码,status为int型数据,占4个字节,高16位不用,低16位中的高8位保存子进程的返回值,低8位中的高一位存core dump标志(程序异常退出时,是否保存运行信息),低7位保存异常退出的信号值。
  • 如何获取子进程的退出码:( status >> 8 ) & 0xff
  • 如何判断程序是否正常退出: status & 0x7f (异常退出信号值>0)
:wait()和waitpid() 函数一次只会回收一个子进程

进程终止

  • 终止场景
    正常退出,结果符合预期
    正常退出,结果不符合预期
    异常退出
  • 终止方式
    main()函数中的return
    exit()函数 (库函数) 退出前会刷新缓冲区,做出退出收尾工作
    _exit()函数 (系统调用接口) 直接退出,释放资源
  • 返回值: 可以通过 echo $? 查看进程的退出码

程序替换

  • 概念:fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。将当前进程的.text、.data替换为所要加载的程序的.text、.data,然后让进程从新的.text第一条指令开始执行,但进程ID不变,换核不换壳。
  • exec函数族
    int execl(const char *path, const char *arg, …);
    int execlp(const char *file, const char *arg, …);
    int execle(const char *path, const char *arg, …, char *const envp[]);
    int execv(const char *path, char *const argv[]);
    int execvp(const char *file, char *const argv[]);
    int execve(const char *path, char *const argv[], char *const envp[]);
  • 有没有P的区别:是否自动到PATH路径下查找指定文件
  • 有没有e的区别;是否自定义环境变量
  • exec函数族一般规律
    exec函数一旦调用成功即执行新的程序,不返回。只有失败才返回,错误值-1。所以通常我们直接在exec函数调用后直接调用perror()和exit(),无需if判断。
    l (list) 命令行参数列表 p (path) 搜素file时使用path变量 v (vector) 使用命令行参数数组
    e (environment) 使用环境变量数组,不使用进程原有的环境变量,设置新加载程序运行的环境变量
    事实上,只有execve是真正的系统调用,其它五个函数最终都调用execve
在这里插入图片描述