怎么实现系统调用wait和exit

637 阅读2分钟

摘要

fork、wait、exit是C语言中的三个连体婴儿,经常一起使用。本文介绍wait和exit的主要流程,并不涉及操作系统的系统调用原理。很简单,一看就懂。

例程

 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <sys/wait.h>
 int main ()
 {
         pid_t fpid; //fpid表示fork函数返回的值
         int count=0;
         int status,i;
         fpid=fork();
         if (fpid < 0)
                 printf("error in fork!");
         else if (fpid == 0) {
                 sleep(10);
                 printf("I am the child process, my process id is %d\n",getpid());
                 count++;
                 exit(123);
         }
         else {
                 printf("I am the parent process, my process id is %d\n",getpid());
                 count++;
                 int res = wait(&status);
                 i = WEXITSTATUS(status);
                 printf("The child exits status:%d\n", i);
         }
         printf("count is: %d\n",count);
         return 0;
 }

编译执行上面的代码,然后,删除下面两行代码再次编译执行。

 int res = wait(&status);
 i = WEXITSTATUS(status);

对比两次执行结果,很容易发现wait的作用:让父进程等待子进程执行结束并且接收子进程的退出状态。

什么场景需要用到wait?当子进程和父进程协同完成一项任务并且在父进程中汇总任务结果的时候。

本文的主题,便是探讨如何实现wait和exit。

wait

在父进程中使用wait。流程如下:

  1. 父进程没有子进程,调用wait后,不阻塞父进程,父进程按照正常流程执行。
  2. 父进程有子进程,但是所有子进程的状态都不是“挂起”状态,把父进程设置成“等待”状态。
  3. 父进程有子进程,而且这个子进程的状态是“挂起”状态,回收子进程占用的进程表,并且解除父进程的阻塞。

exit

在子进程中使用exit。流程如下:

  1. 子进程是C,父进程是P。
  2. 遍历进程表数组,找到进程P。
  3. 如果P是“等待“状态,回收C占用的进程表,解除P的阻塞。
  4. 如果P不是”等待“状态,把C设置为”挂起“状态。
  5. 还没有结束,还需要处理C的子进程。
  6. 把C的子进程”过继“给INIT进程。
  7. INIT进程是什么进程?所有的进程都通过这个进程调用fork产生。
  8. 所谓”过继“,就是把子进程的父进程由C设置成INIT。
  9. 接着判断INIT的状态是否为”等待“状态,然后判断子进程的状态是否为”挂起“状态。
  10. 如果答案都是”是”,把INIT进程设置成”运行“态,回收子进程。
  11. C的其他子进程调用了exit,怎么处理?
  12. 使用一个循环,循环体内,INIT进程调用wait。如此,INIT进程能不断处理调用了exit的其他子进程。