关闭

僵死进程与孤儿进程

279人阅读 评论(0) 收藏 举报
分类:

1.僵死进程与孤儿进程

僵死进程:进程已经退出,但是没有回收内核 PCB 资源的进程叫僵死进程。

孤儿进程:父亲进程先于子进程退出后,这个子进程就是孤儿进程,父亲进程会被转移为 init(pid=1)进程。


僵死进程示例:

#include <stdio.h>
#include <stdlib.h>
#include "apue.h"
#include <sys/wait.h>

void test(int i , void *arg)
{
    printf("helloworld,%d,%s\n",i,(char*)arg);
}

int main(int argc,char *argv[])
{
    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork");
    }
    else if(pid == 0)
    {
        sleep(2);
        printf("child pid:%d\n",getpid());
        exit(10);
    }
    else
    {
        int status;
        pid_t w_pid;
        sleep(20);
        w_pid = waitpid(-1,&status,0);
        printf("w_pid:%d,status:%d\n",w_pid,status>>8);
    }

    exit(0);
}

父进程sleep 20秒时,子进程已经退出,但是没有回收PCB资源(进程PCB资源由父进程回收)。


孤儿进程示例:

#include <stdio.h>
#include <stdlib.h>
#include "apue.h"
#include <sys/wait.h>

void test(int i , void *arg)
{
    printf("helloworld,%d,%s\n",i,(char*)arg);
}

int main(int argc,char *argv[])
{
    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork");
    }
    else if(pid == 0)//子进程
    {
        printf("child pid:%d,parent pid:%d\n",getpid(),getppid());
        sleep(4);
        printf("child pid:%d,parent pid:%d\n",getpid(),getppid());
        exit(10);
    }
    else//父进程
    {
        sleep(2);
        exit(0);
    }
    return 0;
}
父进程比子进程先退出了,子进程由pid==1的进程监管。




2.僵死进程

2.1僵死进程的原因及危害

一个进程在调用exit命令结束自己的生命的时候,其实他并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,他的作用是使进程退出,但是也仅仅限于一个正常的进程变成了一个僵尸进程,并不能完全将其销毁)。在linux进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有的内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态信息供其他进程收集,除此之外,僵尸进程不再占有任何存储空间。他需要他的父进程来为他收尸,如果他的父进程没有安装SIGCHLD信号处理函数调用wait 或 waitpid() 等待子进程结束,有没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时候父进程结束了,那么init进程会自动接手这个子进程,为他收尸,他还是能被清除掉的。但是如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是系统中为什么有时候会有很多的僵尸进程。


由此看出,僵死进程并不会佔用很多的资源。唯一的危害是影响了系统最大进程数,有可能造成后续进程无法分配资源。


2.2.僵死进程演示:

代码:

<span style="font-size:18px;">#include<stdio.h>
#include "apue.h"
#include "fcntl.h"
#include <sys/wait.h>
static void sig_int(int);
#define BUFFSIZE 4096
int glob = 6;
char buf[] = "a write to stdout\n";
const char cmd_init[]="ps -o pid,ppid,state,tty,command"; 
int main(int argc,char *argv[])
{
	int var;
	pid_t pid;
	var = 88;
	if(write(STDOUT_FILENO,buf,sizeof(buf)-1)!=sizeof(buf)-1)
		err_sys("write error");
	printf("before fork\n");
	if((pid = fork())<0)
	{
		err_sys("fork error");
	}
	else if(pid == 0)
	{
		glob++;//子进程运行
		var++;
	}
	else
	{
		sleep(60);//父进程运行
	}
	printf("pid = %d,glob = %d,var = %d\n",getpid(),glob,var);  
	exit(0);
}</span>



查看僵死进程:ps auwx | cut -c 10-15,45-50,63- | grep -i Z 查看僵尸进程pid、名称和进程路径。

僵尸进程的状态为Z,如下图的[first]



2.3.避免zombie的方法
1)在svr4中,如果调用signal或是sigset将SIGCHLD的配置设置为忽略,则不会产生僵死子进程。另外,使用svr4版本sigaction,则可设置SA_NOCLDWAIT标志以避免子进程僵死。Linux中也可以使用这个,在一个程序开始调用这个函数signal(SIGCHLD,SIG_IGN);

2)调用fork两次:第一次调用fork创建子进程,第二次调用创建孙子进程,当子进程退出后,不管父进程是否在循环运行,孙子进程都被init进程接手了,不会产生僵死进程。示例代码:

<span style="font-size:18px;">#include<stdio.h>
#include "apue.h"
#include "fcntl.h"
#include <sys/wait.h>
#define BUFFSIZE 4096
int main(int argc,char *argv[])
{
	pid_t pid;
	if((pid = fork())<0)
		err_sys("fork error");
	else if(pid == 0)//第一个子进程创建
	{	
		if((pid = fork())<0)//第二个子进程创建
			err_sys("fork error");
		else if(pid > 0)
			exit(0);//第一个子进程退出,第二个子进程被init进程托管,不会成为僵死进程
		//第二个子进程运行
		sleep(2);
		printf("second child,parent pid = %d\n",getppid());
		exit(0);
	}
	if(waitpid(pid,NULL,0)!=pid)//父进程:等待第一个子进程退出
		err_sys("fork error");
	 
	exit(0);
}</span>



3)用waitpid等待子进程返回。


3.孤儿进程

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:54131次
    • 积分:1520
    • 等级:
    • 排名:千里之外
    • 原创:95篇
    • 转载:54篇
    • 译文:0篇
    • 评论:3条
    最新评论