Linux进程 -- wait/waitpid函数

僵尸进程: 子进程退出,父进程没有回收子进程资源(PCB),则子进程变成僵尸进程。
孤儿进程: 父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为1号进程init进程。

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);

参数pid:

pid < -1 回收指定进程组内的任意子进程
pid = -1 回收任意子进程
pid = 0 回收和当前调用 waitpid 一个组的所有子进程
pid > 0 回收指定ID的子进程

一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。

(两函数功能)
这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程。

我们知道一个进程的退出状态可以在Shell中用特殊变量$?查看,因为Shell是它的父进程,当它终止时Shell调用waitwaitpid得到它的退出状态同时彻底清除掉这个进程。

如果一个进程已经终止,但是它的父进程尚未调用waitwaitpid对它进行清理,这时的进程状态称为僵尸(Zombie)进程。
任何进程在 刚终止时 都是僵尸进程,正常情况下,僵尸进程都立刻被父进程清理了,为了观察到僵尸进程,我们自己写一个不正常的程序,父进程fork出子进程,子进程终止,而父进程既不终止也不调用wait清理子进程:

#include <unistd.h>
#include <stdlib.h>

int main(void)
{
    pid_t pid=fork();
    if(pid<0) {
        perror("fork");
        exit(1);
    }

    if(pid>0) { /* parent */
        while(1);
    }
    /*child */
    return 0;
}

编译及执行

yu@ubuntu:~/Linux/210/zombie$ gcc zombie.c
yu@ubuntu:~/Linux/210/zombie$ ./a.out
//阻塞

另开一终端,查看进程情况:

yu@ubuntu:~$ ps -aux |grep a.out
yu        2715 94.4  0.0   2088   624 pts/1    R+   23:54   1:10 ./a.out
yu        2716  0.0  0.0      0     0 pts/1    Z+   23:54   0:00 [a.out] <defunct>
yu        2803  0.0  0.1   4532  1976 pts/18   S+   23:55   0:00 grep --color=auto a.out

调用wait/waitpid

若调用成功则返回清理掉的子进程id,若调用出错则返回-1。

父进程调用wait或 waitpid时可能会:

  1. 阻塞(如果它的所有子进程都还在运行)。

  2. 带子进程的终止信息立即返回(如果一个子进程已终止,正等待父进程读取其终止信 息)。

  3. 出错立即返回(如果它没有任何子进程)。

wait和waitpid函数的区别是:

  • 如果父进程的所有子进程都还在运行,调用wait将使父进程阻塞,而调用waitpid时如 果在options参数中指定WNOHANG可以使父进程不阻塞而立即返回0。

  • wait等待第一个终止的子进程,而waitpid可以通过pid参数指定等待哪一个子进程。

可见,调用wait和waitpid不仅可以获得子进程的终止信息,还可以使父进程阻塞等待子进 程终止,起到进程间同步的作用。

如果参数status不是空指针,则子进程的终止信息通过这个参数传出,如果只是为了同步而不关心子进程的终止信息,可以将status参数指定为NULL

waitpid使用实例:

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    pid_t pid;
    pid = fork();

    if (pid < 0) {
    perror("fork failed");
    exit(1);
    }

    if (pid == 0) { //son
    int i;
    for (i = 3; i > 0; i--) {
    printf("This is the child\n");
    sleep(1);
    }
    exit(3);
    } else {    //parent
    int stat_val;
    waitpid(pid, &stat_val, 0); 

    if (WIFEXITED(stat_val))
    printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
    else if (WIFSIGNALED(stat_val))
    printf("Child terminated abnormally, signal %d\n", WTERMSIG(stat_val));
    }

    return 0;
}

编译及执行:

yu@ubuntu:~/Linux/210/waitpid$ gcc waitpid.c

yu@ubuntu:~/Linux/210/waitpid$ ./a.out
This is the child
This is the child
This is the child
Child exited with code 3

你可能感兴趣的:(linux,waitpid)