在我的linux多线程多进程基础专栏中,已和大家一起分享了僵尸线程.在这一篇文章中我将分享僵尸进程以及解决方法wait()函数.
什么是僵尸进程呢?用最通俗易懂的话来说就是子进程执行结束的时候其父进程并没有及时回收该子进程导致成为僵尸进程.如果僵尸进程数量较多,会导致进程表等内核数据结构变得过大,从而影响整个系统的性能和稳定性.我用一段代码给大家演示一下僵尸进程是怎么产生的:
#include <sys/types.h>
#include <unistd.h>
#include<iostream>
int main(void){
pid_t pid=fork();
if(pid>0){
while(1){
std::cout<<"我是父进程"<<std::endl;
sleep(2);
}
}
else if(pid==0){
std::cout<<"我是子进程,我的ID是:"<<getpid()<<",我的父进程ID是:"<<getppid()<<std::endl;
}
}
可以看到这段代码,子进程就执行了一次,但父进程会一直执行,且不会主动回收子进程,这样就将导致僵尸进程.执行代码:
使用linux命令ps aux,查看当前所有进程:
可以看到被白色标记的那一行,出现僵尸进程Z+.
我们使用ctrl+z将程序结束运行,并用kill -s SIGCHLD pid(PS:这里的 pid 替换成父进程的进程 id)杀死僵尸进程.
那么,我们如何避免出现僵尸进程呢,我们需要提醒主进程,当子进程结束的时候,将子进程资源回收,这就是wait函数的功能.
wait函数用于回收子进程资源,其定义如下:
int wait(int *status);
其中,status
是一个指针,用于存储子进程的退出状态.
当一个子进程正常结束时,它的退出状态为 0。如果因异常情况而终止,那么它的退出状态将是非零值。注意:wait()
函数是阻塞的,意味着父进程会暂停执行,直到子进程结束。
回到刚刚那个产生僵尸进程的代码,引入wait()函数进行修改.代码如下:
#include <sys/types.h>
#include <unistd.h>
#include<iostream>
#include <sys/wait.h>
int main(void){
pid_t pid=fork();
if(pid>0){
while(1){
std::cout<<"我是父进程"<<std::endl;
wait(&pid);
sleep(2);
}
}
else if(pid==0){
std::cout<<"我是子进程,我的ID是:"<<getpid()<<",我的父进程ID是:"<<getppid()<<std::endl;
}
}
运行程序并查看系统中所有运行的进程,并未发现僵尸进程,说明wait函数成功指示主函数将子进程资源回收,大功告成!