Wait的背景

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

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

父进程查询子进程的退出状态可以用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);

Wait

pid_t wait(int *status);

当我们用fork启动一个进程时,子进程就有了自己的生命,并将独立地运行。有时,我们需要知道某个子进程是否已经结束了,这样我们可以通过wait安排父进程在子进程结束之后。

status:该参数可以获得你等待子进程的信息

返回值:

on success, returns the process ID of the terminated child;  on  error,  -1  is returned.

特征:

1.wait系统调用会使父进程暂停执行,直到它的任意一个(并不是所有的)子进程结束为止。

2.返回的是子进程的PID,它通常是已经结束了的子进程;

3.状态信息允许父进程判定子进程的退出状态,即从子进程的main函数返回的值或子进程中exit/_exit语句的退出码。

4.如果status不是一个空指针,状态信息将被写入它指向的位置

//示例
int main()
{
    pid_t pid = fork();
    if (pid == -1)
        err_exit("fork");
    else if (pid == 0)
    {
        cout << "In Child, pid = " << getpid() << endl;
        sleep(5);
        exit(10);
    }

    int status;
    int returnPid = wait(&status);
    //两个pid的值相同,但是status的值根本不是10
    cout << "In Parent, returnPid = " << returnPid
         << ", status = " << status << endl;
}



Wait获取status

宏定义

描述

WIFEXITED(status)

WEXITSTATUS(status)

如果子进程正常结束,返回一个非零值

如果WIFEXITED非零,返回子进程退出码

WIFSIGNALED(status)

WTERMSIG(status)

子进程因为捕获信号而终止,返回非零值

如果WIFSIGNALED非零,返回信号代码

WIFSTOPPED(status)

WSTOPSIG(status)

如果子进程被暂停,返回一个非零值

如果WIFSTOPPED非零,返回一个信号代码

//示例
void printStatus(int status)
{
    if (WIFEXITED(status))
    {
        cout << "normal termination, exit status = " << WEXITSTATUS(status) << endl;
    }
    else if (WIFSIGNALED(status))
    {
        cout << "abnormal termination, signal number = " << WTERMSIG(status);
#ifdef WCOREDUMP
        if (WCOREDUMP(status))
            cout << " (core file generated)" << endl;
#else
        cout << endl;
#endif // WCOREDUMP
    }
    else if (WIFSTOPPED(status))
    {
        cout << "child stopped, status number = " << WSTOPSIG(status) << endl;
    }
    else
    {
        cout << "Unknow Stop!" << endl;
    }
}

//测试代码
int main()
{
    pid_t pid = fork();
    if (pid == -1)
        err_exit("fork");
    else if (pid == 0)
        exit(7);

    int status;
    if (wait(&status) == -1)
        err_exit("first wait error");
    printStatus(status);

    pid = fork();
    if (pid == -1)
        err_exit("fork");
    else if (pid == 0)
        abort();

    if (wait(&status) == -1)
        err_exit("first wait error");
    printStatus(status);

    pid = fork();
    if (pid == -1)
        err_exit("fork");
    else if (pid == 0)
        status /= 0;

    if (wait(&status) == -1)
        err_exit("first wait error");
    printStatus(status);

    return 0;
}

查看信号值



Waitpid

pid_t waitpid(pid_t pid, int *status,int options)

等待某个特定进程的结束

参数:

Pid:The value of pid can be:

<-1    meaning wait for any child process whose process group ID is equal to the absolute value of pid.

 -1      meaning wait for any child process(任一子进程).

0       meaning wait for any child process whose process group ID is equal to that of  the calling process(与调用者进程同在一个组的进程).

>0     meaning wait for the child whose process ID is equal to the value of pid.

status:如果不是空,会把状态信息写到它指向的位置(同wait)

options:允许改变waitpid的行为,最有用的一个选项是WNOHANG,它的作用是防止waitpid把调用者的执行挂起

返回值:

如果成功返回等待子进程的ID,失败返回-1

wait与waitpid的区别:

1.在一个子进程终止前, wait 使其调用者阻塞,而waitpid 有一选择项,可使调用者不阻塞。

2.waitpid并不等待第一个终止的子进程:它有若干个选择项,可以控制它所等待的特定进程。

3.wait函数相当于是waitpid函数的一个特例。

waitpid(-1, &status, 0);

僵尸进程(如果不等待...)

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

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

如何避免僵尸进程

方法1:调用wait或者waitpid函数查询子进程退出状态。

方法2:如果不想让父进程挂起,可以在父进程中加入一条语句:signal(SIGCHLD,SIG_IGN);表示父进程忽略SIGCHLD信号,该信号是子进程退出的时候向父进程发送的(表明父进程忽略SIGCHLD信号,一切让Linux内核管理)。

-利用man手册,减少开发难度,提高开发技能

如:Man 7 signal 查找有什么信号可以使应用程序暂停

Linux进程实践(4) --wait避免僵尸进程的更多相关文章

  1. Unix/Linux编程实践教程(一:进程、管道)

    execvp在程序中启动新程序: 用fork创建新进程: forkdemo2代码: 测试fork的时候参考<Linux权威指南>阅读笔记(3)  使用了patch: [root@local ...

  2. 进程——wait与waitpid、僵尸进程与孤儿进程

    僵尸进程:子进程终止了,但是父进程没有回收子进程的资源PCB.使其成为僵尸进程 孤儿进程:父进程先与子进程结束了,使得子进程失去了父进程,这个时候子进程会被1号进程init进程领养,成为孤儿进程 为了 ...

  3. Linux 系统中僵尸进程

    Linux 系统中僵尸进程和现实中僵尸(虽然我也没见过)类似,虽然已经死了,但是由于没人给它们收尸,还能四处走动.僵尸进程指的是那些虽然已经终止的进程,但仍然保留一些信息,等待其父进程为其收尸.配图源 ...

  4. Linux 僵尸进程查杀

    僵尸进程概念 僵尸进程(Zombie process)通俗来说指那些虽然已经终止的进程,但仍然保留一些信息,等待其父进程为其收尸. 书面形式一点:一个进程结束了,但是他的父进程没有等待(调用wait ...

  5. 僵尸进程的产生和避免,如何kill杀掉linux系统中的僵尸defunct进程

    在 Unix系统管理中,当用ps命令观察进程的执行状态时,经常看到某些进程的状态栏为defunct,这就是所谓的"僵尸"进程."僵尸"进程是一个早已 死亡的进程 ...

  6. linux 如何清理僵尸进程

    今天在维护服务器的时候,发现有5个nova-novncproxy的僵尸进程. 26327 ?        S      0:05  \_ /usr/bin/python /usr/bin/nova- ...

  7. 僵尸进程学习 & 进程状态列表 & Linux信号学习

    参考这篇文章: http://www.mike.org.cn/articles/treatment-of-zombie-processes-under-linux/ 在Linux进程的状态中,僵尸进程 ...

  8. Linux下杀僵尸进程办法

    1) 检查当前僵尸进程信息 # ps -ef | grep defunct | grep -v grep | wc -l 175 # top | head -2 top - 15:05:54 up 9 ...

  9. Linux的僵尸进程产生原因及解决方法

    Linux的僵尸进程产生原因及解决方法: 1. 产生原因: 在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,那么他将变成一个僵尸进程.通过ps命令查看 ...

随机推荐

  1. POJ 放苹果问题(递归)

    首先我们想象有一个函数count  f(m,n)可以把m个苹果放到n个盘子中. 根据 n 和 m 的关系可以进一步分析: 特殊的m <=1|| n <= 1时只有一种方法: 当 m < ...

  2. MacOS下安装rvm的几点注意

    如果用以下链接无法下载的话: curl -sSL https://get.rvm.io | bash -s stable #或者 curl -L https://rvm.io | bash -s st ...

  3. java中static特殊性和final(static成员直接被访问,this不能用在static方法中,static不可访问非static)

    java的static关键字 java中,static修饰的成员变量和成员方法叫静态变量和静态方法,不依赖类特定的实例,被类的所有实例共享. 静态变量或类变量 和 实例变量,区别是: 静态变量在内存中 ...

  4. Dynamics CRM 打开数据加密报错及修改用户邮件保存报错的解决方法

    在项目里会碰到在修改用户的电子邮件时报错的问题 然后跑到数据管理里打开数据加密又是报错 解决上述问题只需要做下数据库的更改即可,把标志位置1即可,记得要重启下IIS才能生效 SELECT [Colum ...

  5. Dynamics CRM 本地插件注册器连CRMAn unsecured or incorrectly secured fault was received from the other party

    今天遇到个问题,在本地打开插件注册器连接到远程CRM服务器时报如下问题 但我在CRM服务器上连接注册器是可以打开的,所以不存在账号权限这类的问题了(当然我用的是超管的账号也不可能存在),最后查询得知是 ...

  6. Kafka系列之-自定义Producer

    前面已经讲到了,在Kafka中,Message是由Producer产生的,Producer产生的Message会发送到Topic的指定Partition中.Producer可以有多种形式,也可以由用户 ...

  7. 【伯乐在线】HashMap的工作原理

    本文由 ImportNew - 唐小娟 翻译自 Javarevisited.欢迎加入翻译小组.转载请见文末要求. HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道Ha ...

  8. Android自定义控件及自定义属性

    Android自定义控件及自定义属性 自定义控件 创建自定义控件 自定义一个类,继承View 继承View还是哪个类,取决于你要实现一个什么样的控件 如果你要实现的是一个线性布局的组合控件,就可以继承 ...

  9. FORM开发两种方式实现动态LIST

    方法一:常规的,也是网上比较常见的 1.将目标ITEM的子类信息设置为List,不需要添加列表中元素,不需要初始值. 2.新建一个Procedure,代码如下: PROCEDURE basis_lis ...

  10. Java集合-----java集合框架常见问题

    1什么是Java集合API Java集合框架API是用来表示和操作集合的统一框架,它包含接口.实现类.以及帮助程序员完成一些编程的算法. 简言之,API在上层完成以下几件事: ● 编程更加省力,提高城 ...