文章目录
- 僵尸进程是如何出现的?
- 如何防止僵尸进程产生?
- 使用wait函数
- 使用waitpid函数
- 阻塞等待
- 非阻塞等待——轮询
- 僵尸进程出现后如何解决?
僵尸进程是如何出现的?
一个进程在退出后,操作系统会释放该进程对应的资源,但仍会保留一些信息(pid、退出状态、运行时间等),此时父进程必须主动去获取该信息,若父进程不获取则会导致该信息一直在内存中保留,而该进程就被称为僵尸进程。
如何防止僵尸进程产生?
父进程主动去获取退出的子进程保留下来的信息即可防止僵尸进程的产生,父进程获取的方式有两种:
使用wait函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
返回值:
返回成功被等待进程pid,失败返回-1。
参数:
输出型参数,获取子进程退出状态,若不关心则可传NULL。
使用waitpid函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
返回值:
若options设置为0,返回成功被等待进程pid,失败返回-1
若options设置为WNOHANG,若此时有进程退出则等待成功返回该进程pid,若此时无进程退出返回0
参数:
pid:
pid = -1, 等待任意一个子进程,与wait等效
pid > 0, 等待进程ID与pid相等的子进程
options:
设置为0,则始终等待,直到等待成功/失败
设置为WNOHANG,只等待一次
status参数是一个输出型参数,由操作系统填充,若不关心子进程的退出状态信息传递NULL即可,若关心子进程的退出状态信息则传入一个初始化为0的int变量的指针。
该变量的次低8位为退出码,低7位为终止信号。
于是想要输出正常的退出码与终止信号,需要对status做特殊处理
int exit_code = (status>>8)&0xFF;
int termination_signal = (status>>8)&0x7F;
阻塞等待
wait函数只能是阻塞等待,waitpid函数若options传0也是阻塞等待。
阻塞等待即父进程执行到wait、waitpid函数时会停下来,直到此时有子进程退出,wait去获取信息后父进程才会继续往下执行。
非阻塞等待——轮询
waitpid函数若options传WNOHANG则是非阻塞等待——轮询。
waitpid只执行一次等待,若恰好有进程退出则去获取信息,若无进程退出则返回0,所以若不对waitpid函数做特殊处理,该函数几乎没什么用,此时一般的用法如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t id = fork();
if(id == 0)
{
//child
printf("hello linux\n");
exit(1);
}
//parent
int status = 0;
while(1)
{
pid_t ret = waitpid(id, &status, WNOHANG);
if(ret == -1)
{
//Error
break;
}
else if(ret == 0)
{
//Do other tasks
}
else
{
//Success
break;
}
}
printf("exit_code: %d, termination_signal: %d\n", (status>>8)&0xFF, status&0x7F);
return 0;
}
僵尸进程出现后如何解决?
僵尸进程已经出现后,使用kill -9命令是无法杀死的,因为僵尸进程已经是退出后的进程了(只是有一些退出信息还保留着)。此时可以将该僵尸进程的父进程杀掉,僵尸进程由此变为孤儿进程,被Init进程领养,也由Init进程回收信息,此时僵尸进程就被真正干掉了。