进程控制(二):进程等待

文章目录

  • 进程控制(二)
  • 进程等待
    • wait函数
    • waitpid函数
    • wait/waitpid获取子进程状态码的过程
    • 进程等待相关的宏
  • 总结


进程控制(二)

延续对于上文进程结束,我们继续对于进程控制进行学习,本文我们主要是对于进程等待进行学习,进程等待,我们在前文初步接触进程的时候,我们知道,进程等待是指我们在运行该进程的时候,在等待资源,当有了资源分配后,便可以运行该进程,在本文中,我们认识的进程等待是指,子进程退出时,先进入僵尸状态,然后父进程进行等待(wait/waitpid)来获取子进程退出信息,这个过程叫做进程等待。

进程等待

进程等待,是子进程退出信息被父进程接收时,父进程处于等待状态的一种描述。

进程等待是指通过系统调用wait/waitpid,来进行对子进程进行状态检测与回收的功能。

  • 子进程退出时,如果父进程没有接收信息,那么会导致僵尸进程的问题,造成内存泄漏,所以父进程必须通过进程等待来回收子进程退出信息。(必要
  • 通过回收子进程的退出信息,也可以知道子进程退出码,以及是否出现异常,status。(可选

所以,我们必须要实现进程等待,防止内存泄漏,对于得到的子进程退出信息,我们可以选择性的利用,可有可无,看自己需求。

wait函数

wait函数,可以实现进程等待,只有一个参数,status,输出型参数,可以获得子进程退出信息

进程控制(二):进程等待_第1张图片

wait函数在2号手册上,头文件也可以表明,wait函数以及waitpid函数是系统调用接口,通过该函数来访问操作系统,使得操作系统对于子进程进行回收处理。

进程控制(二):进程等待_第2张图片

core dump,以后会用到,现在不需要掌握,只需要知道,这是用来进行调试的。

#include
#include
#include
#include
#include

#define N 10

void RunChild()
{
   int cnt=5;
   while(cnt)
   {
      printf("Child pid: %d, parent pid: %d\n",getpid(),getppid());//获取pid和ppid
      sleep(1);
      cnt--;
   }
   //printf("Child pid: %d, parent pid: %d\n",getpid(),getppid());//获取pid和ppid
   //sleep(15);
}

int main()
{
    //实现创建子进程,并对于子进程进行等待
    for(int i=0;i<N;i++)
    {
      pid_t id=fork();//创建子进程
      if(id==0)
      {
        RunChild();
        exit(i);//退出码
      }
      //父进程执行下面信息
      printf("create Child proc : %d success\n",id);
    }
    sleep(10);
    return 0;
}

上述代码,我们并没有是wait,会造成内存泄漏,下面我们来通过父进程来接收子进程的退出信息。

#include
#include
#include
#include
#include

#define N 10

void RunChild()
{
   int cnt=5;
   while(cnt)
   {
      printf("Child pid: %d, parent pid: %d\n",getpid(),getppid());//获取pid和ppid
      sleep(1);
      cnt--;
   }
   //printf("Child pid: %d, parent pid: %d\n",getpid(),getppid());//获取pid和ppid
   //sleep(15);
}

int main()
{
    //实现创建子进程,并对于子进程进行等待
    for(int i=0;i<N;i++)
    {
      pid_t id=fork();//创建子进程
      if(id==0)
      {
        RunChild();
        exit(i);//退出码
      }
      //父进程执行下面信息
      //wait;进程等待
      
      printf("create Child proc : %d success\n",id);
   }
    //进程等待
    for(int i=0;i<N;i++)
    {
        //会实现进程的等待
        pid_t id=wait(NULL);//wait等待是随机的,等待还没有被接收信息的子进程,有几个子进程就需要等几次。
        //int status=0;
        //pid_t id=wait(&status);//传地址,操作系统来进行存储子进程退出信息
        if(id>0)
        {
          //printf("wait %d success\n ; exit sig: %d\n",id,WEXITSTATUS(status));
          printf("wait %d success\n",id);
        }
    }
    return 0;
}

waitpid函数

waitpid函数,其拥有三个参数,功能相较于wait更多,可以认为waitpid可以包含wait的功能,wait的功能比较单一,智能获取状态码status,而且是随机等待子进程。

#include 
#include 
 
pid_t waitpid(pid_t pid, int* status, int options);

参数介绍

返回值pid_t:

  • 大于0,表示等待子进程成功,返回值是子进程的pid
  • 小于0,表示等待子进程失败
  • 等于0,表示等待条件还没有就绪,此时父进程可以做自己的事情

pid参数:

  • 大于0,表示等待指定的子进程
  • pid = -1 ,表示等待随机子进程

status参数:

  • NULL,表示不需要子进程的状态码
  • 反之,作为输出型参数,操作系统将子进程退出信息写入status中

options参数:

  • 0,表示阻塞等待
  • WNOHONG,表示非阻塞等待

进程控制(二):进程等待_第3张图片

wait/waitpid获取子进程状态码的过程

wait和waitpid都是系统调用,为什么要通过系统调用函数,而不是库函数来实现该功能,这是因为,由于进程具有独立性,相互不影响,所以一般的函数无法访问到另一进程的内容,而系统调用,可以在全局上(操作系统的角度)来找到子进程PCB,得到状态码

等待流程

  1. 子进程运行完毕后,进入僵尸状态(Z),将退出码信息存储到子进程PCB中(exit_code,exit_signal),释放代码,以及数据,保留task_struct结构体信息。
  2. 父进程通过wait/waitpid,通过系统调用,得到子进程PCB中的退出信息,将推出信息,以位图的方式,写入到int类型的status参数,从而父进程得到子进程的推出信息。

exit_code:表示退出码

exit_signal:表示结束信号,也就是判断是否异常,如果为0,表示正常,如果非零,那就是接收了终止信号 kill -num,其中num==exit_signal

实现方式:

exit_signal == status&0x7F == WIFEXITED(status)

exit_code == status>>8&0xFF == WEXITSTATUS(status)

进程等待相关的宏

WEXITSTATUS(status):表示输出退出码(exit_code)

WNOHONG:表示非阻塞等待,用于waitpid的option参数。

WIFEXITED(status):通过状态码,表示子进程是否正常结束(是否异常),如果正常,返回ture

总结

进程等待,是父进程必须要完成的事情,是为了防止内存泄漏,也是为了知道子进程完成任务情况(由状态码得出结论),主要是了解wait/waitpid函数,以及status参数的构成,为什么能表示进程的三种退出情况,以及waitpid函数的非阻塞等待宏WNOHONG,还有退出码WEXITSTATUS,还有判断子进程是否正常退出的宏命令WIFEXITED。

你可能感兴趣的:(Linux,linux,进程控制,进程等待)