孤儿进程、僵死进程

进程终止

有3种正常终止方法、2中异常终止方法。

正常终止:

1 main函数内执行return语句。

2 调用exit函数,其操作包括调用各终止处理程序(调用atexit时登记),关闭所有标准IO流。(exit用于结束正在运行的整个程序,它将参数返回给OS,把控制权交给操作系统;而return 是退出当前函数,返回函数值,把控制权交给调用函数)

3 调用_exit系统调用函数。exit函数也调用此函数。

异常终止:

1 调用abort函数,产生SIGABRT信号。

2 进程接收到某个信号而终止。进程本身如调用abort函数、其他进程和内核都能产生转送到某一进程的信号。例如进程越出其地址空间访问存储单元,或者除以0,内核就会为该进程产生相应的信号。

不管进程如何终止,最后都会执行内核中的一段代码,它为相应进程关闭所有打开的描述符,释放进程所使用的存储器等。


我们希望终止进程能够通知其父进程它是怎么终止的,对于exit和_exit函数,这依靠传递给它的退出状态(exit status)参数来实现。

在异常终止情况,内核(而非进程)产生一个指示其异常终止原因的终止状态


孤儿进程与僵死进程:

如果父进程在子进程之前终止,子进程变为孤儿进程,那么子进程的父进程都改变为init进程,有init进程领养。实现方法:进程即将终止时,内核遍历检查所有活动进程,判断它是否正要终止的进程的子进程,若是则将其父进程ID改为1,即init进程ID。一旦子进程终止,init进程调用wait函数取得其终止状态。


如果子进程在父进程之前终止,父进程如何得到子进程的终止状态?由于内核为每个终止进程都保存了信息,所以父进程调用wait和waitpid函数可以得到这些信息,包括进程ID,终止状态,以及cpu使用时间总量。


如果父进程未调用wait / waitpid,对终止的子进程进行善后处理,那么这些子进程成为僵死进程么保留的那段信息就不会释放,其进程号一直被占用,但系统能用的进程号有限,如果大量产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。


解决方法:

把产生大量僵死进程的那个父进程杀掉(通过kill发送SIGTERM或者SIGKILL信号),它产生的僵死进程就变成了孤儿进程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源。

具体方法

(1)SIGCHILD信号

#include
#include
#include
#include
#include

static void SIGCHLD_process(int signo);
int main()
{
    pid_t pid;
    if((pid=fork())<0){
       printf("fork error\n");
    }
    if(signal(SIGCHLD,SIGCHLD_process)==SIG_ERR)
        printf("signal error"),exit(1);

    if(pid==0){
        printf("child process id %d\n",getpid());
        exit(0);
    }
    
    printf("father process id %d  will sleep 2s\n",getpid());
    sleep(2);
    
    system("ps -o pid,ppid,state,tty,command");
    exit(0);
}
void SIGCHLD_process(int signo){
    pid_t pid;
    while((pid=wait(NULL))>0)
        printf("child process %d  terminal\n",pid);
}


(2)fork两次


原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程。


#include
#include
#include
#include
int main(){
    pid_t pid;
    if((pid=fork())<0){
        printf("fork error\n");
        exit(1);  
    }
    else if(pid==0){//first child
        if( (pid=fork())<0){
            printf("fork error\n");
            exit(0);
        }
        else if(pid>0){
            printf("first child id %d exit",getpid());
            exit(0);//parent from second fork ==first child exit
        }
        sleep(2);//sleep for 2s waitfor parent exit
        printf("second child id %d ,parent id %d\n",getpid(),getppid());
        exit(0);
        
   }
   if(waitpid(pid,NULL,0)!=pid){//wait for first child
       printf("waitpid error\n");
       exit(1);
   }
   system("ps -o pid,ppid,state,tty,command");
   exit(0);
}


你可能感兴趣的:(Linux)