Linux守护进程3


Linux守护进程3 —— 守护进程分裂子进程


  • 在03 子目录下写test3-1.c,循环10 次,每隔3 秒产生一个子进程,循环完成后,自己进入 死循环操作,每5 秒打印"父进程号+自己的进程号+你的学号+main"信息即可;分裂出的子进 程要求每25 秒打印"父进程号+自己的进程号+你的学号+sub",打印三次后子进程退出;写配 套的makefile 文件,make 后可生成test3-1 可执行文件

    //test3-1.c
    
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <signal.h>
    #include <errno.h>
    #include <sys/wait.h>
    
    #define FORK_NUM 10
    #define SUB_NUM 3
    #define MAIN_SLEEP_TIME 5
    #define SUB_SLEEP_TIME 25
    
    int daemon_init(void){
        pid_t pid;
        if ((pid = fork()) < 0)
    		return -1;
    	else if (pid)   
    		exit(0);	/* parent exit */
    
    	/* child continues */
    	setsid();	/* become session leader */
        chdir("/");	/* change working directory */
    	umask(0);	/* clear file mode creation mask */
    	close(0);    /* close stdin stdout stderr */
    //	close(1);
    	close(2);
    	return 0;
    }
    
    int main(){
    	if (daemon_init() == -1){
    		printf("can't fork self\n");
    		exit(0);
    	}
    
    	pid_t pid;
    	int i;
    	for (i=0; i<FORK_NUM; ++i)
    		if ((pid=fork()) < 0){
    			perror("fork error");
    			exit(errno);
    		}
    		else if(pid==0)
    			break;
    	
    	if(pid){
    		while(1){
    			printf("%5d %5d 1453381 main\n", getppid(), getpid());
    			sleep(MAIN_SLEEP_TIME);
    		}
    	}
    	else{
    		for (i=1; i<=SUB_NUM; ++i){
    			printf("%5d %5d 1453381 sub\n", getppid(), getpid());
    			sleep(SUB_SLEEP_TIME);
    		}
    	}
    	
    	return 0;
    }
    

    测试截图:

  • 分裂出的子进程和守护进程之间的进程id 有何关联?

    子进程的ppid为父进程的pid。

    测试截图:

  • 什么叫僵尸进程?僵尸进程的产生原因?

    僵尸进程: 一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

    原因: 在Linux进程的状态中,僵尸进程是非常特殊的一种,它需要它的父进程来为它收尸,如果他的父进程没安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。

  • 如何杀死僵尸进程?

    一般杀掉进程可用 kill -9 pid命令,但是有些僵尸进程通过此命令不行。可以通过杀掉父进程结束。

    测试截图:

  • 写test3-2.c,要求同test3-1,但是子进程退出后不能存在僵尸进程

    僵尸进程解决办法

    (1)通过信号机制
    子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。

    //test3-2.c 新增函数
    void sig_child(int signo){
    	int status;
    	pid_t pid;
    	while((pid=waitpid(-1, &status, WNOHANG))>0)
    		;
    }
    
    //在main函数第一行添加
    signal(SIGCHLD, sig_child);
    

    在Linux下 可以简单地将 SIGCHLD信号的操作设为SIG_IGN。

    signal(SIGCHLD,SIG_IGN);
    

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

    基于第一种方法实现:

    //test3-2.c
    
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <signal.h>
    #include <errno.h>
    #include <sys/wait.h>
    
    #define FORK_NUM 10
    #define SUB_NUM 3
    #define MAIN_SLEEP_TIME 5
    #define SUB_SLEEP_TIME 25
    
    int daemon_init(void){
        pid_t pid;
        if ((pid = fork()) < 0)
    		return -1;
    	else if (pid)   
    		exit(0);	/* parent exit */
    
    	/* child continues */
    	setsid();	/* become session leader */
        chdir("/");	/* change working directory */
    	umask(0);	/* clear file mode creation mask */
    	close(0);    /* close stdin stdout stderr */
    //	close(1);
    	close(2);
    	return 0;
    }
    
    void sig_child(int signo){
    	int status;
    	pid_t pid;
    	while((pid=waitpid(-1, &status, WNOHANG))>0)
    		;
    }
    
    int main(){
    	if (daemon_init() == -1){
    		printf("can't fork self\n");
    		exit(0);
    	}
    	
    	signal(SIGCHLD, sig_child);
    
    	pid_t pid;
    	int i;
    	
    	for (i=0; i<FORK_NUM; ++i)
    		if ((pid=fork()) < 0){
    			perror("fork error");
    			exit(errno);
    		}
    		else if(pid==0)
    			break;
    	
    	if(pid){
    		while(1){
    			printf("%5d %5d 1453381 main\n", getppid(), getpid());
    			sleep(MAIN_SLEEP_TIME);
    		}
    	}
    	else{
    		for (i=1; i<=SUB_NUM; ++i){
    			printf("%5d %5d 1453381 sub\n", getppid(), getpid());
    			sleep(SUB_SLEEP_TIME);
    		}
    	}
    	
    	return 0;
    }