写在前面
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状态。
---------------------
作者:Nicole xu
来源:CSDN
原文:https://blog.csdn.net/xu1105775448/article/details/80786456
版权声明:本文为博主原创文章,转载请附上博文链接!