曲径通幽论坛

标题: wait() 与 waitpid() --- 等待进程结束 [打印本页]

作者: beyes    时间: 2009-5-30 17:18
标题: wait() 与 waitpid() --- 等待进程结束
当子进程先于父进程退出时,如果父进程没有调用 wait() 和 waitpid() 函数,子进程就会进入僵死状态(wait() 和 waitpid() 可理解为父亲用来收替儿子收尸的工具或东西)。如果父进程调用了 wait() 或 waitpid() 函数,就不会使子进程变为僵尸进程。设置僵死状态的目的是为了维护子进程的信息,以便父进程在以后某个时候获取这些信息。这些信息包括子进程的进程ID,终止状态以及资源利用信息(如 CPU 时间,内存使用量等等)。如果一个进程终止,而它的子进程又处于僵死状态,那么它所有僵死的子进程的父进程ID将被重置为 1,即 init 进程,它将负责清理它们,也就是说 init 将 wait 这些僵死进程,从而去除它们的僵死状态。对于僵死的进程,我们显然不愿意将其留存,因为它们占用了内核中的空间,而且最终会导致我们耗尽进程资源。

下面是 wait() 函数的描述与举例:

函数原型
[C++] 纯文本查看 复制代码

#include <sys/types.h>
pid_t wait(int *stat_loc)


函数描述
wait() 函数是用于使父进程(也就是调用 wait() 的进程)阻塞,直到一个子进程结束或者该进程接到了一个指定的信号为止。如果该父进程没有子进程或者他的子进程已经结束,则 wait() 就会立即返回。

参数说明
stat_loc 是一个整型指针,是该子进程退出时的状态。如果 stat_loc 为空,则代表任意状态结束的子进程;如果 stat_loc 非空,子进程的退出状态信息就会写到这个指针所指向的整型中。

返回值
函数成功时返回子进程的进程号;失败则返回 -1。

测试代码
[C++] 纯文本查看 复制代码

#include
#include
#include
#include
#include
int main()
{
     pid_t pid;
     char *message;
     int n;
     int exit_code;
     printf("fork program starting\n");
     pid = fork();
     switch(pid)
     {
     case -1:
        perror("fork failed");
        exit(1);
     case 0:
        message = "This is the child";
        n = 5;
        exit_code = 88;
        break;
     default:
        message = "This is the parent";
        n = 3;
        exit_code = 0;
        break;
     }
     for(; n > 0; n--) {
         puts(message);
         sleep(1);
     }
     if(pid != 0) {
         int stat_val;
         pid_t child_pid;
         child_pid = wait(&stat_val);

         printf("Child has finished: PID= %d\n", child_pid);
         if(WIFEXITED(stat_val))
             printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
         else
             printf("Child terminated abnormally\n");
     }
     exit(exit_code);
}


运行输出
beyes@linux-beyes:~/C/call/wait> ./wait.exe
fork program starting
This is the parent
This is the child
This is the parent
This is the child
This is the parent
This is the child
This is the child
This is the child
Child has finished: PID= 12418
Child exited with code 88
说明
父进程调用 wait() 后被挂起等待( 此时打开另一个终端,输入命令 ps aux 可以看到父进程的状态为 S ),直到子进程结束为止。子进程正常结束后,wait() 函数返回刚刚结束运行的子进程 pid,宏 WEXITSTATUS 获取子进程的退出码。

在 sys/wait.h 中定义了一些说明状态信息的宏:

WIFEXITED(stat_val)
若子进程正常结束则此宏值非0,若进程异常结束,返回0。

WEXITSTATUS(stat_val)
若 WIFEXITED 非0,则此宏返回子进程中 exit 或 _exit 参数的低 8 位。

WIFSIGNALED(stat_val)
如果子进程异常终止,它就取得一个非0值。

WTERMSIG(stat_val)
如果 WIFSIGNALED 非0,此宏返回子进程异常终止的信号编号。

WIFSTOPPED(stat_val)
如果子进程暂停,它就取得一个非 0 值。

WSTOPSIG(stat_val)
如果 WIFSTOPPED 非0,它返回子进程暂停的信号编号。

如 WEXITSTATUS 在 sys/wait.h 中的定义为:
[C++] 纯文本查看 复制代码
# define WEXITSTATUS(status)    __WEXITSTATUS(__WAIT_INT(status))


而 __WAIT_INT(status) 被定义为:
[C++] 纯文本查看 复制代码
define __WAIT_INT(status)    (status)


在 /bits/waitstatus.h 中对 __WEXITSTATUS(__WAIT_INT(status)) 定义为:
[C++] 纯文本查看 复制代码
/* If WIFEXITED(STATUS), the low-order 8 bits of the status.  */
#define __WEXITSTATUS(status)   (((status) & 0xff00) >> 8)

WIFEXITED(stat_val) 宏在 bits/waitstatus.h 中的定义为:
[C++] 纯文本查看 复制代码

/* If WIFSIGNALED(STATUS), the terminating signal.  */
#define __WTERMSIG(status)      ((status) & 0x7f)
/* Nonzero if STATUS indicates normal termination.  */
#define __WIFEXITED(status)     (__WTERMSIG(status) == 0)

当使用 WIFEXITED(status) 判断子进程为正常终止时,则可用 WEXITSTATUS(status) 取得子进程传递给 exit(),_exit() 或 _Exit() 参数的低 8 位。
作者: beyes    时间: 2009-6-17 20:54
waitpid() 函数

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

函数参数
1、pid 参数
pid > 0 : 等待其进程 ID 等于 pid 的子进程退出
pid = 0 : 等待其组 ID 等于调用进程的组 ID 的的任一子进程
pid < -1 : 等待其组 ID 等于 pid 的绝对值的任一子进程
pid = -1 : 等待任一子进程

2、status 参数
和 wait() 函数中的一样

3、options 参数
WNOHANG  :  若由 pid 指定的子进程不立即可用,则 waitpid() 不阻塞,此时返回值为 0 。
WUNTRACED : 若实现某支持作业控制,则由 pid 指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态。
0 : 同 wait(),阻塞父进程,等待子进程退出。

函数返回值:
正常:返回子进程的进程号。
使用选项 WNOHANG 且没有子进程退出,则返回 0 。
调用出错,返回 -1 。

测试程序
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    pid_t pc, pr;
    pc = fork();
   
    if( pc < 0 )
        printf("Error fork.\\n");
/*子进程*/
    else if ( pc == 0 ) {
        sleep(5);       /*子进程暂停 5s */
        exit(0);
    }            /*子进程退出*/

    else {
        do {    /*调用waitpid(),父进程不阻塞*/
            pr = waitpid(pc, NULL, WNOHANG);
            if( pr == 0 ){
                printf("The child process has not exited\\n");
                sleep(1);  /*子进程未退出,父进程暂停1s*/
            }
        }while( pr == 0 );
    /*子进程退出,打印相应情况*/
    if( pr == pc )
        printf("Get child %d\\n", pr);
    else
        printf("some error occured. %d\\n", pr);
    }
}





欢迎光临 曲径通幽论坛 (http://www.groad.net/bbs/) Powered by Discuz! X3.2