Linux-- 进程的等待的方式比较(wait、witpid、忽略SIGCHILD信号)

写在前面

1.前面已经介绍了,进程等待的相关知识,以及进程等待的必要性:https://blog.csdn.net/xu1105775448/article/details/80171244
2.上一篇关于信号的博客里介绍了Linux下又一种进程等待方式:https://blog.csdn.net/xu1105775448/article/details/80771363

下面通过代码,为了观察,完成同样的功能,体会三种进程等待方式的区别。

三种等待方式

1.wait、waitpid、忽略SIGCHILD信号(忽略SIGCHILD信号只在Linux下有效);
2.wait只能进行阻塞等待,waitpid既可以用于阻塞等待,也可以用于非阻塞等待;

  • waitpid(当waitpid的第三个参数为0时表示阻塞等待,当为WNOHANG时表示非阻塞等待)

3.wait和waitpid函数都可以获得进程的退出码,而忽略SIGCHILD信号只能防止进程变为僵尸进程并不能获得进程的退出码。(所以如果想要获得进程退出码,只能采用wait和waitpid函数)。

wait

1.wait函数原型

pid_t wait(int* status)

//参数:status表示被等待进程的退出码
//返回值:成功返回被等待进程的pid,失败返回-1

2.使用:

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

int main()
{
    pid_t pid = fork();
    if(pid == 0)
    {
        //child
        printf("child pid=%d\n",getpid());
        sleep(5);  //子进程睡5秒之后再退出,在这5秒内父进程会一直等待
        exit(1);
    }
    else if(pid > 0)
    {
        //father
        printf("father\n");
        pid_t ret = wait(NULL);
        printf("exitnum %d\n",ret);  //ret为wait的返回值,成功则返回子进程的pid
    }
    else
    {
        perror("fork()");
    }
    return 0;
}

waitpid

1.waitpid函数原型

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

//返回值:①正常返回时,返回收集到的子进程的pid;②当第三个参数设置为WNOHANG,当调用者发现没有没有已退出的子进程可收集(或者子进程还在运行),则返回0;如果调用出错,返回-1.

//参数:pid表示等待指定子进程的pid,如果为-1表示等待任意一个子进程;status用于获得子进程的退出码,options表示采用何种方式等待(阻塞或非阻塞,0表示阻塞,WNOHANG表示非阻塞)

2.使用

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

int main()
{
    pid_t pid = fork();
    if(pid < 0)
    {
        perror("fork");
        return 1;
    }
    else if( pid == 0)
    {
        //child
        printf("child pid = %d\n",getpid());
        sleep(3);
        exit(2);
    }

    //father
    while(1)
    {
        printf("father do something\n");
        waitpid(-1,NULL,WNOHANG);
        sleep(1);
    }

    return 0;

可以发现:wait与wait的使用方法基本一致

注意:

调用wait或waitpid的次数必须和fork创建子进程的数目一致,如果wait的次数少于子进程的数目,就会导致还有一些子进程任然是僵尸进程;如果wait的次数多于子进程的数目就会导致wait出错,因为已经没有子进程需要等待。

SIGCHILD信号

1.前面我们已经了解到:当子进程退出后,会给父进程发送一个SIGCHILD信号,该信号的默认处理动作是忽略。
2.父进程可以定义SIGCHILD信号的处理行为,就可以让父进程去做其它事,当父进程接收到该信号时再进行进程等待,就不会造成僵尸进程。
3.那么我们可以在SIGCHILD信号的处理函数里面调用wait或waitpid进行等待,这样就可以让父进程及时的发现子进程退出,不用一直阻塞,则父进程就可以做其它的事情。
例如:父进程创建子进程,在信号处理函数里面调用wait:

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

void handel(int signo)
{
    pid_t pid;
    while((pid = waitpid(-1,NULL,WNOHANG)) > 0)
    {
        printf("wait success!\n");
    }
    printf("child exit!\n");
}

int main()
{
    signal(SIGCHLD,handel);
    pid_t pid = fork();
    if(pid < 0)
    {
        perror("fork");
        return 1;
    }
    else if(pid ==  0)
    {
        sleep(3);
        printf("child\n");
        exit(2);
    }

    while(1)
    {
        printf("father do something\n");
        sleep(1);
    }
    return 0;
}                        

4.在Linux下,还可以采用忽略SIGCHILD信号来解决僵尸进程的问题。

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

int main()
{
  signal(SIGCHLD,SIG_IGN);
    pid_t pid = fork();
    if(pid < 0) 
    {
        perror("fork");
        return 1;
    }   
    else if(pid ==  0)
    {
        sleep(3);
        printf("child\n");
        exit(2);
    }   

    while(1)
    {
        printf("father do something\n");
        sleep(1);
    }
    return 0;
}        

运行结果如下:

[root@localhost 三种等待方式]# ./signal
father do something
father do something
father do something
child
father do something
father do something
father do something
...

通过ps aux指令没有看到有进程处于Z状态。

猜你喜欢

转载自blog.csdn.net/xu1105775448/article/details/80786456