unix wait(null)_wait unix - CSDN
  • Unix进程控制—wait函数详解

    千次阅读 2016-05-23 15:59:49
    Unix中父进程与子进程的执行是异步的,父进程可以通过wait函数来获取子进程的结束状态。 函数原型: #include #include pid_t wait(int *statloc); 参数说明: statloc用来保存子进程的结束状态...

    在Unix中父进程与子进程的执行是异步的,父进程可以通过wait函数来获取子进程的结束状态。


    函数原型:

    #include <sys/types.h>

    #include <sys/wait.h>

    pid_t wait(int *statloc);


    参数说明:

    statloc用来保存子进程的结束状态,如果不关心终止状态,则可以把这个设置为空指针。


    返回值:

    若成功则返回进程ID,若出错则返回-1。


    如果在一个父进程中调用wait函数,那么可能的结果如下:

    1)阻塞(如果其所有子进程都还在运行)。

    2)带子进程的终止状态立即返回(如果一个子进程已终止,正等待父进程存取其终止状态)。

    3)出错立即返回(如果它没有任何子进程)。


           当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。因为子进程终止是个异步事件(这可以在父进程运行的任何时候发生),所以这种信号也是内核向父进程发的异步通知。父进程可以忽略该信号,或者提供一个该信号发生时即被调用执行的函数(信号处理程序)。对于这种信号的系统默认动作是忽略它

           如果进程由于接收到SIGCHLD信号而调用wait,则可期望wait会立即返回。但是如果在一个任一时刻调用wait,则进程可能会阻塞。在一般情况下,可以在信号处理函数中调用wait,以避免父进程阻塞。但是这种情况下,也可能父进程先于子进程结束,所以采取手段保证子进程先结束(如在父进程中使用死循环)。

           如果一个子进程已经终止,是一个僵死进程,则wait立即返回并取得该子进程的状态,否则wait使其调用者阻塞直到一个子进程终止。如调用者阻塞而且它有多个子进程,则在其一个子进程终止时,wait就立即返回。因为wait返回终止子进程的进程ID,所以它总能了解是哪一个子进程终止了。


    问题1

    前面提到,wait函数值等待一个子进程结束返回,但是如果一个父进程有多个子进程,剩余的子进程并没有wait函数等待,情况会怎么样呢?

     

    实例代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    int main()
    {
           pid_t pid;
           pid = fork();
           if(pid == 0)
           {
                  sleep(3);
           }
           else if(pid > 0)
           {
                  pid = fork();
                  if(pid == 0)
                  {
                         sleep(5);
                  }
                  else if(pid > 0)
                  {
                         wait(NULL);
                         sleep(10);
                  }
                  else
                  {
                         printf("error\n");
                  }       
           
           }
           else
           {
                  printf("error\n");
           }       
           return 0;
    }

    运行结果:



    结果分析:

           由运行结果可以知道,父进程(进程ID为3651)共有两个子进程(进程ID分别是3652、3653)。但是在父进程中,只调用了一个wait,所以就只有进程ID为3652的子进程的剩余资源被完全清理,而进程ID为3653的子进程变为僵死进程。


    问题2

           如何利用wait回收所有的子进程?

           上面有提到,如果调用wait的函数如果没有任何子进程,那么立即返回,并且返回值是-1。由此,我们可以通过循环调用wait,直到它返回一个错误,说明所有的子进程都已经被回收。

     

    实例代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    int main()
    {
        pid_t pid;
        pid = fork();
        if(pid == 0)
        {
            sleep(3);
        }
        else if(pid > 0)
        {
            pid = fork();
            if(pid == 0)
            {
                sleep(5);
            }
            else if(pid > 0)
            {
                <span style="color:#FF0000;">while(wait(NULL) > 0);</span>
                sleep(10);
            }
            else
            {
                printf("error\n");
            }       
           
        }
        else
        {
            printf("error\n");
        }
           
        return 0;
    }

    运行结果:


    问题3

           在问题二中,两个子进程的结束时刻不同,因此能够通过循环来接收各子进程的结束状态,但是如果两个子进程是同时结束的,那么又会发生什么?






    展开全文
  • wait, waitpid 等待进程状态发送变化 用法 #include &amp;lt;sys/types.h&amp;gt; #include &amp;lt;sys/wait.h&amp;gt; pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int ...

    简介

    wait, waitpid 等待进程状态发送变化

    用法

    #include <sys/types.h>
    #include <sys/wait.h>
    
    pid_t wait(int *status);
    pid_t waitpid(pid_t pid, int *status, int options);
    

    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 terminated; 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

    等待被调用的子进程状态发生变化,这些状态包括:进程终止、收到信号停止,恢复。在进程终止的情况下执行wait允许系统释放与子进程关联的资源,如果没有执行wait则终止的子进程会处于僵尸状态。

    PS:父进程死了,子进程活着。这时候子进程会成为精灵进程,一般后台的常驻都是这种实现。
    :子进程死了,父进程活着,执行wait了释放子进程资源,没有执行资源不释放成为僵尸进程。

    详细用法

    pid:
        < -1   等待所有进程组id等于pid绝对值的子进程。
        -1     等待所有的子进程。
         0     等待所有的进组id等于被调进程组id的子进程。
         > 0   等待进程id等于pid的子进程。
    option:
      0
      WNOHANG   非阻塞,没有进程退出也立即返回。
      WUNTRACED 如果一个子进程暂停函数返回(无法被ptrace跟踪),即使没开此选项也会返回的。
      WCONTINUED 如果一个暂停的子进程通过SIGCONT信号恢复,函数也返回。
    status:
    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.
    WIFEXITED(status):正常结束返回true,exit(返回值),或者主函数returnWEXITSTATUS(status):获取返回码,只有在WIFEXITED(status)为true情况下才使用。
    WIFSIGNALED(status):进程被信号终止返回true。
    WTERMSIG(status):获取终止的信号,只有在WIFSIGNALED(status)为true情况下使用。
    WCOREDUMP(status):如果进程产生corefile返回真,只有在WIFSIGNALED(status)为true情况下使用,并且WCOREDUMP宏存在。
    WIFSTOPPED(status):如果进程被暂停返回true,在WUNTRACED选项下使用。
    WSTOPSIG(status):获得暂停的信号,只有在WIFSTOPPED(status)为true的情况下使用。
    WIFCONTINUED(status):如果进程被SIGCONT信号恢复返回true。
    returnwait(): on success, returns the process ID of the terminated child; on error, -1 is returned.
      waitpid(): on success, returns the process ID of the child whose state has changed; if WNOHANG was        specified and one or more child(ren) specified by pid exist, but have  not  yet changed state,
      then 0 is  returned.  On error, -1 is returned.
    error:
    ECHILD:The calling process does not have any unwaited-for children.
    EINTR  WNOHANG was not set and an unblocked signal or a SIGCHLD was caught.
    EINVAL The options argument was invalid.
    

    举个栗子

    #include <sys/wait.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
       pid_t cpid, w;
       int status;
    
       cpid = fork();
       if (cpid == -1) 
       {
    	   perror("fork");
    	   exit(EXIT_FAILURE);
       }
    
       if (cpid == 0) 
       {            
    	   printf("Child PID is %ld\n", (long) getpid());
    	   if (argc == 1)
    	   {
    			pause();                    /*Wait for signals*/ 
    	   }
    	   _exit(atoi(argv[1]));
    
       } 
       else /* Code executed by parent */
       {                    
    	   do {
    		   w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
    		   if (w == -1) 
    		   {
    			   perror("waitpid");
    			   exit(EXIT_FAILURE);
    		   }
    
    		   if (WIFEXITED(status)) 
    		   {
    			   printf("exited, status=%d\n", WEXITSTATUS(status));
    		   } 
    		   else if (WIFSIGNALED(status)) 
    		   {
    			   printf("killed by signal %d\n", WTERMSIG(status));
    		   } 
    		   else if (WIFSTOPPED(status)) 
    		   {
    			   printf("stopped by signal %d\n", WSTOPSIG(status));
    		   } 
    		   else if (WIFCONTINUED(status)) 
    		   {
    			   printf("continued\n");
    		   }
    	   } while (!WIFEXITED(status) && !WIFSIGNALED(status));
    	   
    	   exit(EXIT_SUCCESS);
       }
       return 0;
    }
    
    

    运行

    ==>gcc waitpid.c -o ww
    ==>./ww 0
    Child PID is 117208
    exited, status=0
    ==>./ww 10
    Child PID is 117221
    exited, status=10
    ==>./ww &
    [1] 117236
    ==>Child PID is 117237
    kill -SIGSTOP 117237
    stopped by signal 19
    ==>kill -SIGCONT 117237
    continued
    ==>kill -SIGTERM 117237
    ==>killed by signal 15
    
    [1]+  Done                    ./ww
    
    展开全文
  • Linux/Unixwait()和waitpid()用法

    千次阅读 2013-08-20 09:04:45
    wait  1.1 简介 wait函数所需头文件:  #include #include wait函数原型: pid_t wait(int *status); 进程一旦调用了 wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到...

    wait 
    1.1 简介


    wait函数所需头文件: 
    #include <sys/types.h>
    #include <sys/wait.h>
    wait函数原型:
    pid_t wait(int *status);

    进程一旦调用了 wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子 进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。 
    参数status用来保存 被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数 情况下,我们都会这样想),我们就可以设定这个参数为NULL,就象下面这样: 
    pid = wait(NULL); 
    如果成 功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD。 
    1.2 实战 
    下面就让我们用一个例子来实战应用一下wait调用,程序中用到了系统调用fork,如果你对此不大熟悉或已经忘记了,请参考fork函数的使用。 
    /* wait1.c */
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <stdlib.h>

    int main()
    {
    pid_t pc,pr;
    pc = fork();
    if (pc < 0)                                                                         /* 如果出错 */
    printf("error ocurred!\n");
    else if (pc == 0)                                                               /* 如果是子进程 */

    printf("This is child process with pid of %d\n",getpid());
    sleep(10);                                                                /* 睡眠10秒钟 */
    }
    else                                                                                 /* 如果是父进程 */
    {                                                                              
    pr = wait(NULL);                                                      /* 在这里等待 */
    printf("I catched a child process with pid of %d\n"),pr); 
    exit(0);



    编译并运行: 
    # cc wait1.c -o wait1
    # ./wait1
    #This is child process with pid of 1508I 
    #catched a child process with pid of 1508 

    可以明显注意到,在第2行结果打印出来前有10秒钟的等待时间,这就是我们设定的让子进程睡眠的时间,只有子进程从睡眠中苏醒过来,它才能正常退出,也就才能被父进程捕捉到。其实这里我们不管设定子进程睡眠的时间有多长,父进程都会一直等待下去,读者如果有兴趣的话,可以试着自己修改一下这个数值,看看会出现怎样的结果。 
    1.3 参数status 
    如果参数status的值不是NULL,wait就会把子进程退出时的状态取出并存入其中,这是一个整数值(int),指出了子进程是正常退出 还是被非正常结束的(一个进程也可以被其他进程用信号结束),以及正常结束时的返回值,或被哪一个信号结束的等信息。由于这些信息被存放在一个整数的不同二进制位中,所以用常规的方法读取会非常麻烦,人们就设计了一套专门的宏(macro)来完成这项工作,下面我们来学习一下其 中最常用的两个: 
    1,WIFEXITED(status) 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值。 (请注意,虽然名字一样,这里的参数status并不同于wait唯一的参数--指向整数的指针status,而是那个指针所指向的整数,切记不要搞混了。) 
    2,WEXITSTATUS(status) 当WIFEXITED返回非零值时,我们可以用这个宏来提取子进程的返回值,如果子进程调用exit(5)退出,WEXITSTATUS(status) 就会返回5;如果子进程调用exit(7),WEXITSTATUS(status)就会返回7。请注意,如果进程不是正常退出的,也就是说,WIFEXITED返回0,这个值就毫无意义。 
    下面通过例子来实战一下我们刚刚学到的内容: 
    /* wait2.c */
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <unistd.h>
    int main()
    {
    int status;
    pid_t pc,pr;
    pc = fork();                                                                             /*调用fork函数*/
    if (pc < 0)                                                                               /* 如果出错 */
    printf("error ocurred!\n");
    else if (pc == 0)                                                                      /* 子进程 */
    {
    printf("This is child process with pid of %d.\n",getpid());
    exit(3);                                                                             /* 子进程返回3 */
    }
    else                                                                                         /* 父进程 */
    {
    pr = wait(&status);
    if (WIFEXITED(status))                                                                    
    {
    printf("the child process %d exit normally.\n",pr);
    printf("the return code is %d.\n",WEXITSTATUS(status));
    }
    else                                                                                  /* 如果WIFEXITED返回零 */
    printf("the child process %d exit abnormally.\n",pr);
    }


    编译并运行: 
    # cc wait2.c -o wait2
    # ./wait2
    #This is child process with pid of 1538.
    #the child process 1538 exit normally.
    #the return code is 3. 
    #the child process 1538 exit abnormally.

    父进程准确捕捉到了子进程的返回值3,并把它打印了出来。 
    当然,处理进程退出状态的宏并不止这两个,但它们当中的绝大部分在平时的编程中很少用到,就也不在这里浪费篇幅介绍了,有兴趣的读者可 以自己参阅Linux man pages去了解它们的用法。 
    waitpid 
    2.1 简介 
    waitpid系统调用在Linux函数库中的所需头文件:
    #include <sys/types.h>
    #include <sys/wait.h>
    waitpid系统调用在Linux函数库中的原型是: 
    pid_t waitpid(pid_t pid,int *status,int options);
    从本质上讲,系统调用waitpid和 wait的作用是完全相同的,但waitpid多出了两个可由用户控制的参数pid和options,从而为我们编程提供了另一种更灵活的方式。下面我们 就来详细介绍一下这两个参数: 
    pid 
    从参数的名字pid和类型 pid_t中就可以看出,这里需要的是一个进程ID。但当pid取不同的值时,在这里有不同的意义。 
    pid>0时,等待进程ID等于 pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。 
    pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。 
    pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。 
    pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。 

    options
     
    options提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANGWUNTRACED两个选项,这是两个常数,可以用"|"运算符把它们连接起来使用,比如: 
    ret=waitpid(-1,NULL,WNOHANG | WUNTRACED); 

    如果我们不想使用它们,也可以把options设为0,如: 
    ret=waitpid(-1,NULL,0); 

    如果使用了 WNOHANG参数调用waitpid,如果没有任何已终止的进程,它也会立即返回,不会像wait那样永远等下去。 
    而WUNTRACED参数,如果子进程进入暂停执行则马上返回,但终止状态不予理睬。
    看到这里,聪明的读者可能已经看出端倪了--wait不就是经过包装的waitpid吗?没错,察看<内核源码目录>/include/unistd.h文件349-352行就会发现以下程序段: 
    static inline pid_t wait(int * wait_stat){return waitpid(-1,wait_stat,0);} 

    2.2 返回值和错误 
    waitpid的返回值比wait稍微复杂一些,一共有3种情况: 
    当正常返回的时候,waitpid返回收集到的子进程的进程ID; 如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0; 如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在; 当pid所指示的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid就会出错返回,这时errno被设置为ECHILD; 
    /* waitpid.c */
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <unistd.h>
    int main()
    {
    pid_t pc, pr;
    pc = fork();
    if (pc < 0)                                                                    /* 如果fork出错 */
    printf("Error occured on forking.\n");
    else if (pc == 0)                                                          /* 如果是子进程 */
    {
    sleep(10);                                                                 /* 睡眠10秒 */
    exit(0);
    }
    else                                                                                /* 如果是父进程 */
    do
    {
    pr = waitpid(pc, NULL, WNOHANG);                      /* 使用了WNOHANG参数,waitpid不会在这里等待 */
    if (pr == 0)                                                               /* 如果没有收集到子进程 */
    {                                                                               
    printf("No child exited\n");
    sleep(1);
    }
    }
    while (pr == 0);                                                       /* 没有收集到子进程,就回去继续尝试 */
    if (pr == pc)
    printf("successfully get child %d\n", pr);
    else
    printf("some error occured\n");

    编译并运行: 
    #gcc waitpid.c -o waitpid
    #./waitpid
    #No child exited
    #No child exited
    #No child exited
    #No child exited
    #No child exited
    #No child exited
    #No child exited
    #No child exited
    #No child exited
    #No child exited
    #successfully get child 1526 
    父进程经过10次失败的尝试之 后,终于收集到了退出的子进程。 
    因为这只是一个例子程序,不便写得太复杂,所以我们就让父进程和子进程分别睡眠了10秒钟和1秒钟,代表它们分 别作了10秒钟和1秒钟的工作。父子进程都有工作要做,父进程利用工作的简短间歇察看子进程的是否退出,如退出就收集它。

     

     

     

    另外还可以参考:http://www.2cto.com/os/201203/124851.html

    展开全文
  • wait、waitpid的作用: 当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。因为子进程终止是个异步事件(这可以在父进程运行的任何时候发生),所以这种信号也是内核向父进程发的异步通知。 父进程可以...

    wait、waitpid的作用:

    • 当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。因为子进程终止是个异步事件(这可以在父进程运行的任何时候发生),所以这种信号也是内核向父进程发的异步通知。
    • 父进程可以忽略该信号,或者提供一个该信号发生时即被调用执行的函数 (信号处理程序)。对于这种信号的系统默认动作是忽略它
    • 当父进程接收到子进程发来的SIGCHLD信号时,可调用wait、waitpid函数来接受子进程的终止状态

    终止状态判断宏:

    • 概念:wait()、waitpid()的参数可以保存子进程的终止状态,#include<sys/wait.h>提供了4个互斥的宏,把终止状态当做宏参数,哪一个宏的值为真,就可选用其他宏来取得退出状态、信号编号等
    WIFEXITED(status)

    若为正常终止子进程返回的状态,则为真

    对于这种情况可执行WEXITSTATUS(status)取子进程传送给exit、_exit、_Exit参数的低8位

    WEXITSTATUS(status) 如果WIFEXITED返回真,则此宏返回子进程的退出码
    WIFSIGNALED(status)

    若为异常终止子进程返回的状态(子进程接到了一个没有捕捉的信号而终止),则为真

    对于 这种情况,可执行WTERMSIG(status) 取使子进程终止的信号编号

    另外,有些实现(非Signle UNIX Specification)定义宏WCOREDUMP(status),若已产生终止进程的core文件,则它返回真

    WTERMSIG(status) 如果WIFSIGNALED返回真,则该宏返回一个信号值
    WIFSTOPPED(status)

    若为当前暂停子进程的返回的状态,则为真

    对于这种情况,可执行WSTOPSIG(status)获取使子进程暂停的信号编号

    WSTOPSIG(status) 如果WIFSTOPPED返回真,则其返回一个信号值
    WIFCONTINUED(status) 若在作业控制暂停后已经继续的子进程返回了状态,则为真(POSIX.1的XSI扩展;仅用于waitpid)

    一、wait()

    #include <sys/wait.h>
    pid_t wait(int *statloc);
    • 参数:一个int值,用来接受子进程的终止状态
    • 返回值:
      • 成功:返回子进程ID
      • 出错:返回0/-1
    • 注意事项:
      • wait()如果不关心子进程的终止状态,参数可以设置为NULL
      • 因为返回值为子进程的进程ID,所以父进程就可以根据这个返回值来判断是哪个子进程终止的

    wait的特点

    • 如果一个进程没有任何子进程,若该进程调用wait(),则wait()立即出错返回
    • wait()调用被一个信号中断时,也可能返回另一种出错
    • 如果父进程的子进程都还在运行时调用wait(),则父进程就处于阻塞,等待子进程终止并返回一个终止状态
    • 如果父进程调用wait(),当任意一个子进程终止时,wait()就获得该子进程的终止状态立即返回

    演示案例

    • wait()获取子进程终止状态,然后使用pr_exit打印终止状态的类型
    #include<sys/wait.h>
    #include<unistd.h>
    #include<stdio.h>
    #include<stdlib.h>
    void pr_exit(int exit)
    {
        if (WIFEXITED(status))
            printf("normal termination, exit status = %d\n",WEXITSTATUS(status));
        else if (WIFSIGNALED(status))
            printf("abnormal termination, signal number = %d%s\n",WTERMSIG(status));
    
    #ifdef WCOREDUMP
        WCOREDUMP(status) ? " (core file generated)" : "");
    #else
        "");
    #endif
    
        else if (WIFSTOPPED(status))
            printf("child stopped, signal number = %d\n",WSTOPSIG(status));
    }
    
    int main(void)
    {
        pid_t pid;
        int status;
    
        if((pid=fork()<0){
            perror("fork error");
        }
        else if(pid==0)
            exit(7);
        if(wait(&status)!=pid)
            perror("wait error");
        pr_exit(status);
    
        if((pid=fork()<0){
                perror("fork error");
            }
        else if(pid==0)
            abort();
        if(wait(&status)!=pid)
            perror("wait error");
        pr_exit(status);
    
        if((pid=fork()<0){
            perror("fork error");
         }
        else if(pid==0)
            status /=0;
        if(wait(&status)!=pid)
            perror("wait error");
        pr_exit(status);
    
        return 0;
    }
    
    • 运行结果:

    二、waitpid()

    #include <sys/wait.h>
    pid_t waitpid(pid_t pid, int *statloc, int options);

    与wait()的不同之处

    • 父进程调用wait(),当任意一个子进程终止时,wait()就获得该子进程的终止状态立即返回。因此用来等待指定的子进程。早起的UNIX必须调用wait(),然后将其返回的进程ID和所期望的进程ID相比较,直至等待到特定的进程时才获取相关信息,比较麻烦
    • waitpid()提供等待指定子进程的功能

    参数

    参数1:

    • pid== -1:等待任一子进程。于是在这一功能方面waitpid与wait等效
    • pid>0:等待进程ID与pid相等的子进程
    • pid==0:等待组ID等于调用进程组ID的任一子进程
    • pi <-1:等待组ID等于pid 的绝对值的任一子进程

    参数2:

    • 存放子进程的终止状态

    参数3:

    • options参数使我们能进一步控制waitpid的操作。此参数或者是0(默认操作),或者是下表中常数的按位或运算的结果 
    WCONTINUED 若实现支持作业控制,那么由pid指定的任一子进程在停止后已经继续,但其状态尚未报告,则返回其状态(POSIX.1的XSI扩展)
    WNOHANG 没有已终止的子进程时,则waitpid不阻塞。此时其返回值为0
    WUNTRACED 若某实现支持作业控制,而由pid指定的任一子进程已处于停止状态,并且其状态自停止依赖还未报告过,则返回其状态,WIFSTOPPED宏确定返回值是否对应于一个停止的子进程

    返回值:

    • 成功:返回子进程ID
    • 出错:返回0/-1
    • 若waitpid()不阻塞,返回0

    特点

    • 对于waitpid,如果指定的进程或进程组不存在,或者参数pid指定的进程不是调用进程的子进程,都可能出错
    • 相对于wiat(),waitpid提供了一个wait的非阻塞版本,有时候希望获取一个子进程的状态,但不想阻塞
    • waitpid通过WUNTRACED、WCONTINUED选项支持作业控制

    演示案例

    • 代码注释:我们不想等待子进程终止,也不希望第一个子进程处于僵死状态直到父进程终止,实现这一要求的诀窍是调用fork两次
    • 第二个子进程调用sleep以保证在打印父进程ID时,第一个子进程已终止
    • 在fork之后,父、子进程都可以继续执行,并且无法预知哪一个会先执行。在fork之后,如果不使第2个子进程休眠,那么它可能比其父进程先执行,于是它先打印的父进程ID将是创建它的父进程,而不是init进程
    #include<sys/wait.h>
    #include<unistd.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include <sys/wait.h>
    int main(void)
    {
        pid_t pid;
        if ((pid = fork()) < 0) {
            perror("fork error");
        } 
        else if (pid == 0) /* first child */
        { 
            if ((pid = fork()) < 0)
                perror("fork error");
            else if (pid > 0)
                exit(0);
    
            sleep(2);
            printf("second child, parent pid = %ld\n", (long)getppid());
            exit(0);
        }
        if (waitpid(pid, NULL, 0) != pid) /* wait for first child */
            perror("waitpid error");
    
        exit(0);
    }
    
    

    运行结果:

    • 当原先的进程(也就是exec本程序的进程)终止时,shell打印其命令行指示符:因为主进程通过waitpid等待的是第一个子进程,第一个子进程比第二个父进程先结束,所以当第一个子进程结束时,父进程通过waitpid接收到终止状态也接着结束了。所以程序结束先打印命令行提示符(因为主进程结束了)
    • 当打印完命令行提示符之后:后面的语句再打印出来,因为第二个子进程被init接管了,最后执行打印,并且会让你再按一下回车结束

    演示案例

    • 一个简单的程序,父进程等待子进程,获得子进程的退出码 
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    int main()
    {
        pid_t pid;
        if((pid=fork())<0){
            perror("fork");
            exit(1);
        }
        else if(pid==0){
            printf("I am child process,pid=%d\n",getpid());
            sleep(5);
            exit(66);
        }else{
            int status;
            pid_t childPid;
            childPid=waitpid(-1,&status,0);
            if(WIFEXITED(status) && (childPid==pid)){
                printf("wait child success,exit code is %d\n",WEXITSTATUS(status));
            }else{
                perror("wait child failed\n");
                exit(2);
            }
            exit(0);
        }
    }
    

    演示案例

    •  演示一个waitpid非阻塞的版本
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    int main()
    {
        pid_t pid;
        if((pid=fork())<0){
            perror("fork");
            exit(1);
        }
        else if(pid==0){
            printf("I am child process,pid=%d\n",getpid());
            sleep(5);
            exit(66);
        }else{
            int status;
            pid_t childPid=0;
            //非阻塞等待,直到一个子进程结束
            do{
                childPid=waitpid(-1,&status,WNOHANG);
            }while(childPid==0);
            if(WIFEXITED(status) && (childPid==pid)){
                printf("wait child success,exit code is %d\n",WEXITSTATUS(status));
            }else{
                perror("wait child failed\n");
                exit(2);
            }
            exit(0);
        }
    }
    

    三、waitid()

    #include <sys/wait.h>
    int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
    //返回值:成功返回0;出错,返回-1
    • 功能

      • 与waitpid相似,waitid允许一个进程指定要等待的子进程,但它使用两个单独的参数表示要等待的子进程所属的类型,而不是将此与进程ID或进程组ID组合成一个参数。
      • id参数的作用域idtype的值相关
    • 注意事项:Linux 3.2.0、Mac OS X 10.6.8、Solaris 10支持waitid。Mac OS X 10.6.8并没有设置siginfo结构中的所有信息

    参数

    • 参数1:
    P_PID 等待一特定进程,id包含要等待子进程的进程ID
    P_PGID 等待一特定进程组的任一子进程;id包含要等待子进程的进程组ID
    P_ALL 等待任一子进程;忽略id
    • 参数2:
    • 参数3:指向siginfo结构的指针。该结构包含了造成子进程状态改变有关信号的详细信息
    • 参数4:
      • 下面各标志的按位或运算,指示调用者关注哪些状态变化
      • WCONTINUED、WEXITED、WSTOPPED这3个常量之一必须在options参数中指定
    WCONTINUED 等待一进程,它以前曾被停止,此后又已继续,但其状态尚未报告
    WEXITED 等待已退出的进程
    WNOHANG 如无可用的子进程退出状态,立即返回而非阻塞
    WNOWAIT 不破坏子进程退出状态。该子进程退出状态可由后续的wait、waitid、waitpid调用取得
    WSTOPPED 等待一进程,它已经停止,但其状态尚未报告

    四、wait3()、wait4()

    #include <sys/types.h>
    #include <sys/wait.h>
    #include <sys/time.h>
    #include <sys/resource.h>
    pid_t wait3(int *statloc, int options, struct rusage *rusage);
    pid_t wait4(pid_t pid, int *statloc, int options, struct rusage *rusage);
    
    //返回值:成功返回进程ID。出错,返回-1
    • 功能
      • 大多数UNIX系统提供了另外两个函数wait3和wait4。这两个函数是从UNIX系统的BSD分支延袭下来的。它们提供的功能比POSIX.函数wait和waitpid、waitod所提供的分别要多一个,这与附加参数rusage有关。该参数要求内核返回由终止进程及其所有子进程使用的资源概况
      • 资源信息包括用户CPU时间总量、系统CPU时间总量、缺页次数、接收到信号的次数等
    • 注意事项
      • 有关细节请参阅getrusage(2)手册页。这些资源信息只包括终止子进程,并不包括处于停止状态的子进程(这种资源信息与7.11节中所述的资源限制不同)
    • 列出了各个wait函数所支 持的不同的参数:

    展开全文
  • UNIX再学习 -- exit 和 wait 系列函数

    千次阅读 2017-04-25 16:29:22
    我们一开始讲进程环境时,就有提到了。进程有 8 种方式使进程终止。其中 5 种为正常终止,它们是:(1)在 main 函数中执行 return(2)调用 exit 函数,并不处理文件描述符,多进程(3)调用 _exit 或 _Exit(4)...
  • 1)wait()函数 在进程中通过fork函数可以创建父子进程,在两个进程中,父子进程可以执行自己的进程,进程的执行也有先后顺序,当调用该函数时可以是进程阻塞成等待状态,直到一个子进程或者该进程收到一个信号...
  • unix环境高级编程 wait和waitpid调用

    千次阅读 2008-06-05 17:51:00
    1.8.1 简介2002 年 3 月 01 日本文介绍了Linux下的进程概念,并着重讲解了与Linux进程管理相关的4个重要系统调用getpid,fork,exit和_exit,辅助一些例程说明了它们的特点和使用方法。 关于进程的一些必要知识 先 看...
  • exit()与wait-()函数

    2019-04-23 14:57:36
    exit()与wait*()函数 exit()与wait*()函数进程控制这节的知识我就基本只是把书上的整理了一下, 仅仅只是个人觉得有用的整理了下。exit()函数 _Exit() : 其目的是为进程提供一种无需运行终止处理程序或信号...
  • 有朋友疑惑“为什么有了wait函数族还需要使用SIGCHLD信号?”。本文详细地阐述UNIX系统中wait函数族和SIGCHLD信号的关系。  一、unix中僵尸进程的含义  关于unix中僵尸进程的含义: 凡是父进程没有调用wait函数获得...
  • 作用:wait()函数会暂停当前进程的执行,直到有子进程的结束,此时wait()函数会返回子进程结束状态值,由status接收,如果对这个子进程是如何结束的并不关心,那么这个参数也可以设为NULL。如果执行成功会返回子进程...
  • 有朋友疑惑“为什么有了wait函数族还需要使用SIGCHLD信号?”。本文详细地阐述UNIX系统中wait函数族和SIGCHLD信号的关系。 一、unix中僵尸进程的含义 关于unix中僵尸进程的含义,APUE2是这样定义: In UNIX ...
  • Java Process中waitFor()的问题

    万次阅读 2014-10-30 20:39:47
    在编写Java程序时,有时候我们需要调用其他的诸如exe,shell这样的程序或脚本。在Java中提供了两种方法来启动其他程序: (1) 使用Runtime的exec()方法 (2) 使用ProcessBuilder的start()方法 。Runtime和...
  • #include <sys/wait.h>pid_t wait(int *status); pid_t waitpid(pid_t pid, int *statusPtr, int options);现在要知道调用wait或waitpid的进程可能会发生什么情况: 如果其所有子进程都在运行,则阻塞。 如果一个子...
  • TIME_WAIT状态与解决方法

    千次阅读 2016-08-21 16:24:25
    TIME_WAIT存在的两个理由: 1 可靠的实现TCP全双工连接的终止 2 允许老的重复的分节在网络上的消逝 第一个:如果客户端不维持TIME_WAIT状态,那么将响应给服务端一个RST,该分节被服务器解释成一个错误。如果TCP...
  • UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他, 那么他将变成一个僵尸进程. 但是如果该进程的父进程已经先结束了,那么该进程就不会变成僵尸进程,因为每个进程结束的时候,系统都会...
  • 有朋友疑惑“为什么有了wait函数族还需要使用SIGCHLD信号?”。本文详细地阐述UNIX系统中wait函数族和SIGCHLD信号的关系。一、unix中僵尸进程的含义关于unix中僵尸进程的含义,APUE2是这样定义:In UNIX System ...
  • 字节对齐问题引起的sem_wait 段错误

    千次阅读 2018-08-28 11:36:19
    今天写代码用到了信号量,使用sem_timedwait();时报出段错误如下: 0x00007ffff6109418 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54 54 ../sysdeps/unix/sysv/linux/raise.c: No ...
  • 1.wait和waitpid函数 当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。因为子进程终止是个异步事件,所以这种信号也是内核向 父进程发的异步通知。父进程可以选择忽略信号,或者提供一个该信号的处理...
  • 很多资料讲了关于TCP的CLOSING和CLOSE_WAIT状态以及所谓的优雅关闭的细节,多数侧重与Linux的内核实现(除了《UNIX网络编程》)。本文不注重代码细节,只关注逻辑。所使用的工具,tcpdump,packetdrill以及ss。 关于...
  • wait函数族和SIGCHLD信号的关系 2012-08-09 13:28:43 分类: LINUX 一、wait()和waitpid()函数的区别 pid_t wait(int *status)  进程一旦调用了wait,就立即阻塞自己,由wait自动分析是 ...
1 2 3 4 5 ... 20
收藏数 37,004
精华内容 14,801
关键字:

unix wait(null)