linux系统编程之进程(六):父进程查询子进程的退出,wait,waitpid


本节目标:

  • 僵进程
  • SIGCHLD
  • wait
  • waitpid

一,僵尸进程

当一个子进程先于父进程结束运行时,它与其父进程之间的关联还会保持到父进程也正常地结束运行,或者父进程调用了wait才告终止。

子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程,它只保留最小的一些内核数据结构,以便父进程查询子进程的退出状态。

进程表中代表子进程的数据项是不会立刻释放的,虽然不再活跃了,可子进程还停留在系统里,因为它的退出码还需要保存起来以备父进程中后续的wait调用使用。它将称为一个“僵进程”。

二,如何避免僵尸进程

  • 调用wait或者waitpid函数查询子进程退出状态,此方法父进程会被挂起。
  • 如果不想让父进程挂起,可以在父进程中加入一条语句:signal(SIGCHLD,SIG_IGN);表示父进程忽略SIGCHLD信号,该信号是子进程退出的时候向父进程发送的。

三,SIGCHLD信号

当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止)

如果不想让子进程编程僵尸进程可在父进程中加入:signal(SIGCHLD,SIG_IGN);

如果将此信号的处理方式设为忽略,可让内核把僵尸子进程转交给init进程去处理,省去了大量僵尸进程占用系统资源。

示例:

#include <stdio.h><unistd.h><signal.h><stdlib.h>

 main((signal(SIGCHLD,SIG_IGN) ===(pid == -(pid == (pid >  

结果:

如果成功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD。

man帮助:

DESCRIPTION
       All of these system calls are used to wait for state changes in a child
       of the calling process, and obtain information about  the  child  whose
       state  has changed.  A state change is considered to be: the child ter-
       minated; the child was stopped by a signal; or the child was resumed by
       a  signal.  In the case of a terminated child, performing a wait allows
       the system to release the resources associated with  the  child;  if  a
       wait  is not performed, then the terminated child remains in a "zombie"
       state (see NOTES below).

       If a child has already changed state, then these calls  return  immedi-
       ately.   Otherwise  they  block until either a child changes state or a
       signal handler interrupts the call (assuming that system calls are  not
       automatically restarted using the SA_RESTART flag of sigaction(2)).  In
       the remainder of this page, a child whose state has changed  and  which
       has  not  yet  been  waited upon by one of these system calls is termed
       waitable.

wait() :
    The wait() system call suspends execution of the calling process  until
    one  of  its children terminates.  The call wait(&status) is equivalent
    to:

        waitpid(-1, &status, 0);

If status is not NULL, wait() and waitpid() store status information in
      the  int  to  which  it points.  This integer can be inspected with the
      following macros (which take the integer itself as an argument,  not  a
      pointer to it, as is done in wait() and waitpid()!):

      WIFEXITED(status)
             returns true if the child terminated normally, that is, by call-
             ing exit(3) or _exit(2), or by returning from main().

      WEXITSTATUS(status)
             returns the exit status of the  child.   This  consists  of  the
             least  significant  8 bits of the status argument that the child
             specified in a call to exit(3) or _exit(2) or  as  the  argument
             for  a  return  statement  in main().  This macro should only be
             employed if WIFEXITED returned true.

      WIFSIGNALED(status)
             returns true if the child process was terminated by a signal.

    WTERMSIG(status)
             returns the number of the signal that caused the  child  process
             to terminate.  This macro should only be employed if WIFSIGNALED
             returned true.

      WCOREDUMP(status)
             returns true if the child produced  a  core  dump.   This  macro
             should  only  be  employed  if  WIFSIGNALED returned true.  This
             macro is not specified in POSIX.1-2001 and is not  available  on
             some  Unix  implementations  (e.g.,  AIX, SunOS).  Only use this
             enclosed in #ifdef WCOREDUMP ... #endif.

      WIFSTOPPED(status)
             returns true if the child process was stopped by delivery  of  a
             signal;  this  is  only possible if the call was done using WUN-
             TRACED or when the child is being traced (see ptrace(2)).

      WSTOPSIG(status)
             returns the number of the signal which caused the child to stop.
             This  macro should only be employed if WIFSTOPPED returned true.


   WIFCONTINUED(status)
       (since Linux 2.6.10) returns  true  if  the  child  process  was
       resumed by delivery of SIGCONT.

  • wait系统调用会使父进程暂停执行,直到它的一个子进程结束为止。
  • 返回的是子进程的PID,它通常是结束的子进程
  • 状态信息允许父进程判定子进程的退出状态,即从子进程的main函数返回的值或子进程中exit语句的退出码。
  • 如果status不是一个空指针,状态信息将被写入它指向的位置

可以上述的一些宏判断子进程的退出情况:

<sys/wait.h><stdlib.h><unistd.h> main(=(pid < (pid == = wait(&(ret <

结果:

<sys/wait.h><stdlib.h><unistd.h> main(=(pid < (pid == = wait(&(ret <

结果:

<sys/wait.h><stdlib.h><unistd.h> main(=(pid < (pid == = waitpid(pid,&(ret <

结果:

QQ截图20130713112838

可知,option设为WNOHANG,父进程不会等到子进程的退出,即不会阻塞,如果没有子进程退出则立即返回-1,

相关内容