守护进程简单的说就是在后台运行的服务,它的特点是后台运行,脱离终端。如何实现一个守护进程呢?为了阐述清楚,先解释些预备知识。

1.      预备知识

1.1.   进程,进程组和会话关系

         进程组是进程的集合,会话又是进程组的集合。何为会话?会话就是用户登陆linux系统时建立的一个连接。每个会话又有个领头进程。进程组可以理解为shell中输入的一条命令,比如一个linux可执行文件,执行后会启动一个进程,这个进程又fork出一些子进程,这些进程就是一个进程组,而这些进程组的最初始者就为进程组长。一个session只能有一个前台进程组,用于和终端交互,前台进程组的领头组长一般是bash

会话、进程组、进程与控制终端的关系

1.2.   僵尸进程和孤儿进程

僵尸进程:子进程死亡,父进程并没有调用waitwaitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

孤儿进程:父进程死亡,子进程成了“孤儿”被init进程收购。

如果进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。

2.      Demo

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <signal.h>

#include <sys/param.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <time.h>

 

#define SHUTDOWNTIME  120   // shutdown OS 2 minuteslater

 

void init_daemon(void)

{

    int pid;

    int i;

    if(pid=fork())

        exit(0);        //是父进程,结束父进程

    else if(pid< 0)

        exit(1);        //fork失败,退出

    //是第一子进程,后台继续执行

    setsid();           //第一子进程成为新的会话组长和进程组长

    //并与控制终端分离

    if(pid=fork())

        exit(0);        //是第一子进程,结束第一子进程

    else if(pid< 0)

        exit(1);        //fork失败,退出

    //是第二子进程,继续

    //第二子进程不再是会话组长

    for(i=0;i<NOFILE;++i)  //关闭打开的文件描述符

        close(i);

 

   chdir("/");      //改变工作目录到/tmp

    umask(0);           //重设文件创建掩模

    return;

}

 

void sig_child(int signo)

{

      pid_t        pid;

      int        stat;

      //处理僵尸进程

     while ((pid = waitpid(-1, &stat, WNOHANG)) >0)

             printf("child %dterminated.\n", pid);

}

void GetTime(int *ps32Time)

{

    characCmdStr[100]; 

    char acTemp[4];

    FILE *fp;

    int i;

   signal(SIGCHLD,sig_child);

    for(i = 0; i <3; i++)

    {

    sprintf(acCmdStr,"%s%d","date | cut -d\" \" -f4 | cut -d: -f ",i + 1);

    fp = popen(acCmdStr,"r"); // 注意因为popen为重启一个进程执行shell命令,可能会产//生僵尸进程,需要signal处理

    fgets(acTemp,sizeof(acTemp),fp);

     *(ps32Time + i) =atoi(acTemp);    

    }

    pclose(fp);  

}

int main()

{

   

    ints32StartTime[3];

    int s32CurTime[3];

    ints32TimeInterval = 0;

    init_daemon();

   GetTime(s32StartTime);

    

    while(1)

    {

        GetTime(s32CurTime);

        s32TimeInterval = (s32CurTime[0] - s32StartTime[0]) * 3600 +(s32CurTime[1] - s32StartTime[1]) * 60 + s32CurTime[2] - s32StartTime[2];

        if(s32TimeInterval < 0)

         {

             s32TimeInterval += 24 * 3600;

         }

        

        if(s32TimeInterval >= SHUTDOWNTIME)

         {

                // dowith something    

                                 }  

        sleep(60); //sleep 60s

     }

   

    return 0;

}                               }  

        sleep(60); //sleep 60s

     }

   

    return 0;

}