Linux:进程等待wait函数

进程等待的作用:

  • 父进程在它的执行代码中调用进程等待的方法,等待子进程退出,防止子进程变成僵尸进程;
  • 也就是说,进程等待是父进程调用某个接口进行等待,父进程等待子进程退出回收子进程的资源,防止子进程变成僵尸进程

进程等待的方法(如何让父进程进行进程等待):wait函数和waitpid函数

wait函数:

pid_t wait (int* status)

  • 参数是一个指针类型,但是该指针类型并不是要传递一个指针参数,而是一个输出型参数;
  • 将wait函数内部计算的某个结果通过status变量返回给调用者;
  • 之前所接触的输出型参数有:swap函数中的参数,交换两数的值函数进行传址,将swap的结果传到外部

在编码时有一个代码规范:
如果是输入型,参数定义成引用;
如果是输出或者输入输出参数,参数定义成指针;

wait函数的四个特性:

1.输出型参数,与其对应的有:

  • 输入型参数→调用者给被调用函数传参;
  • 输入输出型参数;

2.int* status是一个指针类型占四个字节,但是实际中只使用到后两个字节,将这两个字节分为三部分:

  • 退出码 + coredump标志位 + 退出信号
  • 高位字节表示退出码;
  • 低位的一个字节又被分为两个部分,
    第一个比特位表示coredump标志位
    后七个比特位表示退出信号
    Linux:进程等待wait函数_第1张图片

退出码:程序正常退出时用到

  • main函数的return返回时,return后的数字就是退出码
  • exit和_exit中的参数就是退出码

coredump标志位,退出信号是程序异常退出时用到:

  • 为0表示该进程在退出时没有内存镜像文件的产生(也就是说没有coredump产生)
  • 为1则有镜像文件产生,当前程序退出异常
  • 退出信号进程异常退出时收到的几号信号

  • 进程正常退出时coredump标志位和退出信号被置为全0;
  • 退出码则是进程正常退出给的数值;
  • 异常退出coredump标志位和退出信号会有相应的数;
  • 也就是说程序正常退出只有退出码起作用,异常退出则要看标志位和退出信号

用退出信号判断进程是否正常退出:

产生coredump文件不能判断进程是否正常退出的原因:

  • 程序在运行时崩溃(例如解引用空指针),该进程会收到崩溃信号;
  • 该信号可能会让进程产生一个coredump文件,这个文件并不是收到崩溃信号就一定会产生。
  • 是否产生coredump文件取决于:
    磁盘硬限制,空间大小不足;
    系统的软限制,进程可以产生coredump文件但是系统不让其产生

1.判断是否有退出信号

  • 正常退出时,退出信号7位全=0;异常退出,退出信号>0;
  • 所以
    int _status=wait(&status);
    status & 0xfff ffff;,等于0正常退出,>0异常退出

2.判断coredump标志位

  • (ststus >> 7) & 0x1;

3.判断退出码

  • (ststus >> 8) & 0xff;也就是按位与上八个一

使用wait函数阻止子进程变成僵尸进程

Linux:进程等待wait函数_第2张图片

运行情况:

  • 父进程创建子进程后,子进程走else if,父进程走else语句;
  • 因为父子进程是抢占式执行,那么可能是父进程先执行wait并退出,子进程变成孤儿进程;
  • 也可能是子进程先执行先退出,父进程等待退出

  • 实际不管谁先运行,父进程都是正常结束的;
  • 因为这里牵扯到阻塞的概念,父进程一旦调用wait函数后,当子进程没有退出前,wait函数是不会返回;
  • 父进程调用wait函数,wait函数就压到父进程的栈帧上,子进程没有退出,父进程栈帧是不会销毁的,也就是说wait函数不会出栈返回

阻塞:

阻塞概念:当调用结果返回之前,当前的执行流会被挂起,并在得到结果之后返回

  • 或者说:调用结果返回前,当前线程会被挂起,并在得到结果之后返回
  • 例如:父进程被wait函数阻塞,父进程就会被挂起,必须等到子进程结束后才能返回
  • 使用上述代码,只需给父进程处加一个死循环即可;
  • 运行后通过pstack+父进程进程号查看父进程栈帧;

Linux:进程等待wait函数_第3张图片
Linux:进程等待wait函数_第4张图片
父进程一直在wait,并没有返回;

对阻塞和非阻塞理解:
1.子进程一种在运行;

  • 阻塞:父进程等待子进程运行完后退出;这就是阻塞
  • 非阻塞:父进程不等子进程运行是否运行完毕就退出,这样可能会导致孤儿进程;这就是非阻塞

2.子进程已退出

  • 阻塞:父进程正常退出
  • 非阻塞:父进程正常退出

对于两种非阻塞的情况,父进程都是直接退出,但是两种情况父进程退出后,一种正常一种不正常

waitpid函数

wait函数的实现是调用waitpid函数实现
Linux:进程等待wait函数_第5张图片

  • 非阻塞模式下waitpid函数返回是没有等待子进程的;
  • waitpid函数在非阻塞模式下只调用一次并且也没等待到子进程退出,再不去调用该函数;
  • 等到子进程退出后子进程就会变成僵尸进程;
  • 所以在非阻塞模式下需要搭配循环;

你可能感兴趣的:(Linux系统编程,linux,操作系统)