Linux僵尸进程


一、僵尸进程简介

  • 如果父进程比子进程先退出,子进程将被1号进程托管(这也是一种让程序在后台运行的方法)。
  • 如果子进程比父进程先退出,而父进程没有处理子进程退出的信息,那么,子进程将成为僵尸进程
  • 示例:
#include <iostream>
#include <cstring>
#include <unistd.h>

using namespace std;

int main()
{
    // 父进程没有退出之前,子进程退出
    // 子进程将变成僵尸进程
    if (fork() == 0) return 0;

    while (true)
    {
        cout << "子进程持续运行" << endl;
        sleep(1);
    }
}

在这里插入图片描述
在这里插入图片描述

二、僵尸进程的危害

  • 内核为每个子进程保留了一个数据结构,包括进程编号、终止状态、使用CPU时间等。
  • 父进程如果处理了子进程退出的信息,内核就会释放这个数据结构,父进程如果没有处理子进程退出的信息,内核就不会释放这个数据结构,子进程的进程编号将一直被占用。
  • 系统可用的进程编号是有限的,如果产生了大量的僵尸进程,将因为没有可用的进程编号而导致系统不能产生新的进程。

三、避免僵尸进程的方法

  1. 子进程退出的时候,内核会向父进程发送SIGCHLD信号,如果父进程用signal(SIGCHLD,SIG_IGN)通知内核,表示自己对子进程的退出不感兴趣,那么子进程退出后会立即释放数据结构。
  • 示例:
#include <iostream>
#include <cstring>
#include <signal.h>
#include <unistd.h>

using namespace std;

int main()
{
    // 父进程没有退出之前,子进程退出
    // 忽略由于子进程退出发出的信号,将不会产生僵尸进程
    signal(SIGCHLD, SIG_IGN);
    if (fork() == 0) return 0;

    while (true)
    {
        cout << "子进程持续运行" << endl;
        sleep(1);
    }
}
  1. 父进程通过wait()/waitpid()等函数等待子进程结束,在子进程退出之前,父进程将被阻塞等待。
    pid_t wait(int *stat_loc);
    pid_t waitpid(pid_t pid, int *stat_loc, int options);
    pid_t wait3(int *status, int options, struct rusage *rusage);
    pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);
  • 头文件:<sys/types.h><sys/wait.h>
  • 返回值pid是子进程的编号。
  • stat_loc是子进程终止的信息:
    a)如果是正常终止,宏WIFEXITED(stat_loc)返回真,宏WEXITSTATUS(stat_loc)可获取终止状态;
    b)如果是异常终止,宏WTERMSIG(stat_loc)可获取终止进程的信号。
  • 示例1(通过exit(x)或者return x正常退出):
#include <iostream>
#include <cstring>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>

using namespace std;

int main()
{
    if (fork() > 0)
    {
        int stat_loc;
        // 阻塞父进程,直至子进程终止,获取子进程编号
        pid_t pid = wait(&stat_loc);
        // 正常终止
        if (WIFEXITED(stat_loc))
        {
            cout << "子进程:" << pid << "正常终止,终止状态是" << WEXITSTATUS(stat_loc) << endl;
        }
        // 异常终止
        else
        {
            cout << "子进程:" << pid << "异常终止,终止信号是:" << WTERMSIG(stat_loc) << endl;
        }
    }
    else
    {
	    while (true)
	    {
	        cout << "子进程即将退出..." << endl;
	        sleep(5);
	        exit(3);
	    }
	}
}

在这里插入图片描述

  • 示例2(通过信号异常退出-内存泄漏):
#include <iostream>                                                                                                                                                          
#include <cstring>                                                                                                                                                           
#include <signal.h>                                                                                                                                                          
#include <sys/wait.h>                                                                                                                                                        
#include <sys/types.h>                                                                                                                                                       
#include <unistd.h>  

using namespace std;                                                                                                                                                   
int main()                                 
{                                          
    if (fork() > 0)                        
    {                                      
        int stat_loc;
        // 阻塞父进程,直至子进程终止,获取子进程编号
        pid_t pid = wait(&stat_loc);
        // 正常终止                        
        if (WIFEXITED(stat_loc))
        {                                  
            cout << "子进程:" << pid << "正常终止,终止状态是:" << WEXITSTATUS(stat_loc) << endl;
        }                                  
        // 异常终止                        
        else                               
        {                                  
            cout << "子进程:" << pid << "异常终止,终止信号是:" << WTERMSIG(stat_loc) << endl;
        }                                  
    }                                      
    else                                   
    {                                      
        while (true)                       
        {                                  
            // 内存泄漏导致子进程异常终止
            int* pi = 0;
            *pi = 100;
            exit(0);                       
        }                                  
    }                                      
}    

在这里插入图片描述

  • 示例3(通过信号异常退出-接收信号):
#include <iostream>                                                                                                                                                          
#include <cstring>                                                                                                                                                           
#include <signal.h>                                                                                                                                                          
#include <sys/wait.h>                                                                                                                                                        
#include <sys/types.h>  
#include <unistd.h>

using namespace std;

int main()
{
    if (fork() > 0)
    {
        int stat_loc;
        // 阻塞父进程,直至子进程终止,获取子进程编号
        pid_t pid = wait(&stat_loc);
        // 正常终止
        if (WIFEXITED(stat_loc))
        {
            cout << "子进程:" << pid << "正常终止,终止状态是:" << WEXITSTATUS(stat_loc) << endl;
        }
        // 异常终止
        else
        {
            cout << "子进程:" << pid << "异常终止,终止信号是:" << WTERMSIG(stat_loc) << endl;
        }
    }
    else
    {
        while (true)
        {
            sleep(50);
            exit(0);
        }
    }
}

在这里插入图片描述

  1. 如果父进程很忙,可以捕获SIGCHLD信号,在信号处理函数中调用wait()/waitpid(),就是将对子进程退出的处理放在了信号处理函数中实现。
#include <iostream>                                                                                                                                                          
#include <cstring>                                                                                                                                                           
#include <signal.h>                                                                                                                                                          
#include <sys/wait.h>                                                                                                                                                        
#include <sys/types.h>                                                                                                                                                       
#include <unistd.h>                                                                                                                                                          
                                                                                                                                                                             
using namespace std;                                                                                                                                                         
                                                                                                                                                                             
// 子进程终止的信号处理函数                                                                                                                                                  
void func(int sig)                                                                                                                                                           
{                                                                                                                                                                            
    int stat_loc;                                                                                                                                                            
    pid_t pid = wait(&stat_loc);                                                                                                                                             
    if (WIFEXITED(stat_loc))    
    {
    	cout << "子进程:" << pid << "正常终止,终止状态是:" << WEXITSTATUS(stat_loc) << endl;
    }
    else
    {
        cout << "子进程:" << pid << "异常退出,终止信号是:" << WTERMSIG(stat_loc) << endl;
    }
}

int main()
{
    // 子进程终止的信号处理
    signal(SIGCHLD, func);
    if (fork() > 0)
    {
        while (true)
        {
            cout << "父进程忙于执行任务....." << endl;
            sleep(1);
        }
    }
    else
    {
        while (true)
        {
            sleep(3);
            int *pi = 0;
            *pi = 10;
        }
    }
}

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值