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. Azure AI 服务之语音识别

    笔者在前文<Azure AI 服务之文本翻译>中简单介绍了 Azure 认知服务中的文本翻译 API,通过这些简单的 REST API 调用就可以轻松地进行机器翻译.如果能在程序中简单的集 ...

  2. Django Model field reference

    ===================== Model field reference ===================== .. module:: django.db.models.field ...

  3. Android布局概述

    布局 布局定义用户界面的视觉结构,如Activity或应用小部件的 UI.您可以通过两种方式声明布局: 在 XML 中声明 UI 元素.Android 提供了对应于 View 类及其子类的简明 XML ...

  4. ubuntu蓝牙音响配对成功但在声音设置中无法设置 解决

    ubuntu蓝牙音响配对成功但在声音设置中无法设置 解决 首先,连接蓝牙 但是,在声音设置中如下: 都没有发现设备??? 打开终端输入: ~$ pactl load-module module-blu ...

  5. IntelliJ Idea 设置 Dialyzer

    IntelliJ Idea 设置 Dialyzer(金庆的专栏)Erlang开发使用IDEA IDE可以设置外部工具Dialyzer, 然后就可以直接Tools->External Tools ...

  6. Redis工作系列之一 与 Memcached对比理解

         近期公司项目在使用Redis,这几年Redis很火,Redis也常常被当作Memcached的挑战者被提到桌面上来.关于Redis与Memcached的比较更是比比皆是.然而,Redis真的 ...

  7. 【安卓开发】Android为什么选择binder

    Binder (Android技术内幕): 在上面这些可供选择的方式中,Android使用得最多也最被认可的还是Binder机制. 为什么会选择Binder来作为进程之间的通信机制呢?因为Binder ...

  8. 手把手图文并茂教你用Android Studio编译FFmpeg库并移植

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52661331 之前曾写过一篇&l ...

  9. T-SQL动态查询(1)——简介

    起因: 由于最近工作需要及过去一直的疑问,所以决定着手研究一下动态SQL.由于离开一线开发有点年头了,很多技巧性的东西没有过多研究,作为DBA和<SQL Server性能优化与管理的艺术> ...

  10. Jstorm与RocketMQ整合

    如果是经常关注阿里巴巴的朋友们,看到我这篇博客的题目,就知道我在参加今年的中间件比赛. 好了,废话不说,开始了. 首先我们知道,rocketmq的consumer有两种,一种是DefaultMQPus ...