首页 > 代码库 > Wait VS Waitpid

Wait VS Waitpid

Waitwaitpid出现的原因(SIGCHLD):

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

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

      父进程查询子进程的退出状态可以用wait/waitpid函数

 

Man-page

       #include <sys/types.h>
       #include <sys/wait.h>

       pid_t wait(int *status);

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

DESCRIPTION
       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 (see NOTES below).

       If a child has already changed state, then these  calls  return  immediately.   Otherwise they  block  until  either  a child changes state or a signal handler interrupts the call (assuming that system calls are not automatically restarted using the SA_RESTART flag  of sigaction(2)).   In the remainder of this page, a child whose state has changed and which has not yet been waited upon by one of these system calls is termed waitable.

Wait

描述:

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

 

函数原型:

  

 pid_t wait(int *status);


函数参数:

    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不是一个空指针,状态信息将被写入它指向的位置

 

示例:

#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <errno.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <iostream>
using namespace std;

int main()
{
    pid_t pid = fork();
    if (pid == -1)
    {
        perror("fork");
        return -1;
    }

    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 << "status = " << WEXITSTATUS(status) << endl;
    }
    else if (WIFSIGNALED(status))
    {
        cout << "signal = " << WTERMSIG(status) << endl;
    }
    else if (WIFSTOPPED(status))
    {
        cout << "stop = " << WSTOPSIG(status) << endl;
  }
    else
    {
        cout << "Unknow Stop!" << endl;
    }
}

int main()
{
    pid_t pid = fork();
    if (pid == -1)
    {
        perror("fork");
        return -1;
    }
    if (pid == 0)
    {
        sleep(1);
        abort();
    }

    pid = fork();
    if (pid == -1)
    {
        perror("fork");
        return -1;
    }
    if (pid == 0)
    {
        sleep(2);
        exit(255);
    }

    int status1,status2;
    wait(&status1);
    wait(&status2);
    printStatus(status1);
    printStatus(status2);

    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 VS. waitpid

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

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

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

waitpid(-1, &status, 0);


 

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

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

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

 

~如何避免僵尸进程

    调用wait或者waitpid函数查询子进程退出状态,此方法父进程会被挂起。

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

 

 

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

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


 

System系统调用

功能:

       system()函数调用“/bin/sh -c command”执行特定的命令,阻塞当前进程直到command命令执行完毕,system函数执行时,会调用forkexecvewaitpid等函数。

 

原型:

 

  int system(const char *command);


返回值:

    如果无法启动shell运行命令,system将返回127;出现不能执行system调用的其他错误时返回-1。如果system能够顺利执行,返回那个命令的退出码。

 

示例:

int main()
{
    system("ls -la");

    return 0;
}

自己动手写system

int mySystem(const char *command)
{
    if (command == NULL)
    {
        errno = EAGAIN;
        return -1;
    }
    pid_t pid = fork();
    if (pid == -1)
    {
        perror("fork");
        exit(-1);
    }
    else if (pid == 0)
    {
        execl("/bin/sh","sh","-c",command,NULL);
        exit(127);
    }

    int status;
    waitpid(pid,&status,0);
    //wait(&status);

    return WEXITSTATUS(status);
}

int main()
{
    mySystem("ls -la");

    return 0;
}


Wait VS Waitpid