《unix高级环境编程》进程控制——进程等待

wait 函数和 waitpid 函数

        当一个进程正常或异常终止时,内核会向其父进程发送 SIGCHLD 信号。父进程可以为这个信号提供一个信号处理程序,也可以选择忽略,系统对这种信号默认是忽略。当进程调用 wait 或 waitpid 函数可能会发生以下的情况:注意:如果进程是由于接收到 SIGCHLD 信号而调用 wait 函数,则可期望 wait 立即返回;但是如果是在任意时刻调用 wait,则进程可能会发生阻塞。

  1. 如果其所有子进程都还在运行,则发生阻塞。
  2. 如果一个子进程已经终止,正在等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。
  3. 如果没有任何子进程,则立即出错返回。
/* 等待进程终止 */

/*
 * 函数功能:等待一个进程终止;
 * 返回值:若成功则返回进程ID、0;若出错则返回-1;
 * 函数原型:
 */
#include <sys/wait.h>

pid_t wait(int *statloc);

pid_t waitpid(pid_t pid, int *statloc, int option);

/*
 * 说明:
 * 参数statloc是指向存放终止进程的终止状态单元的指针;如果不在意这些信息,则可设为NULL;
 * pid和option参数是控制waitpid操作;
 */
/*
 * pid参数及作用如下
 * pid == -1;   等待任一子进程,此时waitpid和wait功能一样;
 * pid > 0;     等待其进程ID与pid相等的子进程;
 * pid == 0;    等待其组ID与调用进程组ID相等的任一子进程;
 * pid < -1;    等待其组ID与pid绝对值相等的任一子进程;
 */
/*
 * 参数option可以是0,也可以是以下参数按位"或"组成:
 * WCONTINUED   若实现支持作业控制,由pid指定的任一子进程在暂停后已经继续,但其状态尚未报告,则返回其状态;
 * WNOHANG      若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时其返回值0;
 * WUNTRACED    若某实现支持作业控制,而由pid指定的任一子进程已处于暂停状态,并且其状态自暂停以来还未报告,则返回其状态;
 */
这两个函数的区别如下:

  1. 在一个子进程终止之前,wait函数使其调用者阻塞,而 waitpid 有一个选项 option,根据选项的不同值可使其调用者不发生阻塞。
  2. waitpid 并不一定要等待在其调用后的第一个子进程终止,根据不同选项,可以控制自己感兴趣要等待的进程。
waitpid 提供了 wait 没有提供的三个功能:

  1. waitpid 可以等待一个特定的子进程,而wait 则返回任一终止子进程的状态;
  2. waitpid 提供一个非阻塞的 wait 版本;
  3. waitpid 支持作业控制;

可以用以下宏查看进程的终止状态:

/* 检查 wait 和 waitpid 所返回的终止状态的宏.....
 * WIFEXITED(status)    若为正常终止子进程返回的状态,则为真;对于这种情况可执行WEXITSTATUS(status),
 *                      取子进程传给exit,_exit或_Exit参数的低8位;
 *
 * WIFSIGNALED(status)  若为正常终止子进程返回的状态,则为真;对于这种情况可执行WTERMSIG(status),
 *                      取使子进程终止的信号编号;另外,有些实现定义宏WCONREDUMP(status),若已产生终止进程的core文件,则返回真;
 *
 * WIFSTOPPED(status)   若为当前暂停子进程的返回状态,则为真;对于这种情况可执行WSTOPSIG(status),取使子进程暂停的信号编号;
 *
 * WIFCONTINUED(status) 若在作业控制暂停后已经继续的子进程返回的状态,则为真;
 *
 */
测试程序:

#include <sys/wait.h>
#include "apue.h"

void pr_exit(int status)
{
    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 stoped, signal number = %d\n", WSTOPSIG(status));
}

int main(void)
{
    pid_t pid;
    int status;

    if((pid = fork()) < 0)
        err_sys("fork error");
    else if(0 == pid)   /* in child process */
        exit(7);
    if(wait(&status) != pid)    /* wait for child process */
        err_sys("wait error");
    pr_exit(status);    /* print its status */

    if((pid = fork()) < 0)
        err_sys("fork error");
    else if(0 == pid)   /* in child process */
        abort();        /* generated SIGABRT */
    if(wait(&status) != pid)    /* wait for child process */
        err_sys("wait error");
    pr_exit(status);    /* print its status */

    if((pid = fork()) < 0)
        err_sys("fork error");
    else if(0 == pid)   /* in child process */
        status /= 0;        /* divide by 0 generated SIGFPE */
    if(wait(&status) != pid)    /* wait for child process */
        err_sys("wait error");
    pr_exit(status);    /* print its status */

    exit(0);
}
输出结果:

normal termination, exit status = 7
abnormal termination, signal number = 6(core file generated)
abnormal termination, signal number = 8(core file generated)
        输出的结果只是对不同状态的打印,即在正常终止子进程、异常终止子进程、当前暂停子进程的状态。从打印信息可以看到,该子进程发生正常终止和异常终止。

程序2:

#include <sys/wait.h>
#include "apue.h"

void pr_exit(int status)
{
    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 stoped, signal number = %d\n", WSTOPSIG(status));
}

int main(void)
{
    pid_t pid,fpid;
    int status;

    if((pid = fork()) < 0)
        err_sys("fork error");
    else if(0 == pid)   /* in child process */
    {
        printf("child process, sleep 5s.\n");
        sleep(5);
        printf("child process, normal exit.\n");
        exit(0);
    }
    else
    {
        fpid = wait(&status);/* wait for child process */
        if(fpid < 0)
            err_sys("wait error");
        printf("father process, child process ID: %d\n",fpid);
        pr_exit(status);    /* print its status */
    }
    exit(0);
}
        以上程序是在现有进程中 fork 创建一个子进程,在 fork 返回的子进程中先睡眠5秒,然后正常退出;在 fork 返回的父进程中,wait 等待子进程终止,然后打印子进程终止状态信息,最后正常退出。输出结果如下:

child process, sleep 5s.
child process, normal exit.
father process, child process ID: 6065
normal termination, exit status = 0

waitid 函数

       该函数类似于上面的 waitpid 函数功能,也是允许一个进程指定要等待的子进程,但是 waitid 使用单独的参数表示要等待的子进程的类型,而不是将此与进程 ID 或进程组 ID 组合成一个参数。

/*
 * waitid 函数
 * 函数功能:等待一个进程终止;
 * 返回值:若成功则返回0,若出错则返回-1;
 * 函数原型:
 */
#include <sys/wait.h>
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

/*
 * 参数说明:
 * idtype 是以下的常量:
 * P_PID    等待一个特定的进程:id包含要等待的子进程的进程ID;
 * P_PGID   等待一个特定进程组的任一子进程:id包含要等待的子进程的进程组ID;
 * P_ALL    等待任一子进程:忽略id;
 *
 * options 是以下参数按位"或"组成:
 * WCONTINUED   等待一个进程,暂停后已经继续,但其状态尚未报告;
 * WEXITED      等待已退出的进程;
 * WNOHANG      若无可用的子进程退出状态,立即返回而非阻塞;
 * WNOWAIT      不破坏子进程退出状态,该子进程退出状态可由后续的 wait、waitid 或 waitpid 调用取得;
 * WSTOPPED     等待一个进程,它已经暂停,但其状态尚未报告;
 *
 * infop 是指向 siginfo 结构的指针,该结构包含有关引起子进程状态改变的生成信号的详细信息;
 */
程序测试:

#include "apue.h"
#include <sys/wait.h>
#include <unistd.h>

int main(void)
{
        pid_t pid, fpid;
        siginfo_t info;

        if((pid = fork()) < 0)
            err_sys("fork error.");
        else if(pid == 0)
        {
            sleep(5);
            _exit(0);
        }
        while((fpid = waitid(P_PID,pid,&info,WEXITED)) == 0)
        {
            printf("terminated process success exit,and process ID: %d.\n",pid);
            sleep(1);
        }
        exit(0);
}
        该程序是在现有进程使用 fork 创建一个子进程,在 fork 返回的子进程中睡眠 5s 后正常退出;在 fork 返回的父进程调用 waitid 函数等待与子进程的进程 ID 与 pid 相等子进程退出状态,waiti 成功则返回0,打印一条信息;输出结果如下:

terminated process success exit,and process ID: 6589.

wait3 和 wait4 函数

        函数 wait3 和 wait4 提供的功能比函数 wait,waitpid 和 waitid 所提供的功能要多一个,这与附加参数 rusage 有关,该参数要求内核返回由终止进程及其所有子进程使用的资源汇总。

/*
 * wait3 和 wait4 函数
 * 函数功能:等待一个进程终止;
 * 返回值:若成功则返回进程ID,若出错则返回-1;
 * 函数原型:
 */
#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);

参考资料:

《UNIX 高级环境编程》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值