如何确保只有一个守护进程正在运行?

问题描述:

我的代码,以守护进程的过程是:如何确保只有一个守护进程正在运行?

static int daemonize(const char *lockfile) 
{ 
    pid_t pid, sid, parent; 
    int lfp = -1; 
    char buf[16]; 

    /* already a daemon */ 
    if (getppid() == 1) return 1; 

    /* Each copy of the daemon will try to 
    * create a file and write its process ID 
    * in it. This will allow administrators 
    * to identify the process easily 
    */ 
    /* Create the lock file as the current user */ 
    if (lockfile && lockfile[0]) { 
     lfp = open(lockfile,O_RDWR|O_CREAT,LOCKMODE); 
     if (lfp < 0) { 
      syslog(LOG_ERR, "unable to create lock file %s, code=%d (%s)", 
        lockfile, errno, strerror(errno)); 
      exit(EXIT_FAILURE); 
     } 
    } 

    /* If the file is already locked, then to ensure that 
    * only one copy of record is running. The filelock function will fail 
    * with errno set to EACCESS or EAGAIN. 
    */ 
    if (filelock(lfp) < 0) { 
     if (errno == EACCES || errno == EAGAIN) { 
      close(lfp); 
      //return(1); 
      exit(EXIT_FAILURE); 
     } 
     syslog(LOG_ERR, "can't lock %s: %s", lockfile, strerror(errno)); 
     exit(EXIT_FAILURE); 
    } 
    ftruncate(lfp, 0); 
    sprintf(buf, "%ld", (long)getpid()); 
    write(lfp, buf, strlen(buf)+1); 

    /* Drop user if there is one, and we were run as RUN_AS_USER */ 
    if (getuid() == 0 || geteuid() == 0) { 
     struct passwd *pw = getpwnam(RUN_AS_USER); 
     if (pw) { 
      syslog(LOG_NOTICE, "setting user to " RUN_AS_USER); 
      setuid(pw->pw_uid); 
     } 
    } 

    /* Trap signals that we expect to recieve */ 
    signal(SIGCHLD,child_handler); 
    signal(SIGUSR1,child_handler); 
    signal(SIGALRM,child_handler); 

    /* Fork off the parent process */ 
    pid = fork(); 
    if (pid < 0) { 
     syslog(LOG_ERR, "unable to fork daemon, code=%d (%s)", 
       errno, strerror(errno)); 
     exit(EXIT_FAILURE); 
    } 
    /* If we got a good PID, then we can exit the parent process. */ 
    if (pid > 0) { 
     /* Wait for confirmation from the child via SIGTERM or SIGCHLD, or 
      for two seconds to elapse (SIGALRM). pause() should not return. */ 
     alarm(2); 
     pause(); 

     exit(EXIT_FAILURE); 
    } 

    /* At this point we are executing as the child process */ 
    parent = getppid(); 

    /* Cancel certain signals */ 
    signal(SIGCHLD,SIG_DFL); /* A child process dies */ 
    signal(SIGTSTP,SIG_IGN); /* Various TTY signals */ 
    signal(SIGTTOU,SIG_IGN); 
    signal(SIGTTIN,SIG_IGN); 
    signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */ 
    signal(SIGTERM,SIG_DFL); /* Die on SIGTERM */ 

    /* Change the file mode mask */ 
    umask(0); 

    /* Create a new SID for the child process */ 
    sid = setsid(); 
    if (sid < 0) { 
     syslog(LOG_ERR, "unable to create a new session, code %d (%s)", 
       errno, strerror(errno)); 
     exit(EXIT_FAILURE); 
    } 

    /* Change the current working directory. This prevents the current 
     directory from being locked; hence not being able to remove it. */ 
    if ((chdir("/")) < 0) { 
     syslog(LOG_ERR, "unable to change directory to %s, code %d (%s)", 
       "/", errno, strerror(errno)); 
     exit(EXIT_FAILURE); 
    } 

    /* Redirect standard files to /dev/null */ 
    freopen("/dev/null", "r", stdin); 
    freopen("/dev/null", "w", stdout); 
    freopen("/dev/null", "w", stderr); 

    /* Tell the parent process that we are A-okay */ 
    kill(parent, SIGUSR1); 
    return 0; 
} 

我想在我启动使用时间运行我的程序只有一个实例:

service [script] start 

但每当这个命令执行两个或更多时候,它会在运行状况下创建相同数量的守护进程。我想摆脱这种行为。任何建议将不胜感激。

+0

阅读[这个答案](http://stackoverflow.com/questions/688343/reference-for-proper-handling-of-pid-file-on-unix),并要非常小心的竞态条件和错误。 – Emmet 2014-04-03 17:51:50

请勿使用文件锁定;相反,使用O_EXCL标志open(),如果该文件已存在,则该标志将失败,并显示EEXIST。这通常是用pid文件完成的,因为它无论如何都需要是独占的。

+0

@geekosaur但是在带有fcntl函数的filelock()中,我正在以独占写锁的F_WRLCK模式打开pid文件。所以这应该与open()中的O_EXCL模式相同。 – 2011-05-06 21:19:05

+0

@Sushant:这可能是,但它更难做到(因此更容易出错和竞争条件)。一般来说,我更喜欢更简单的方法,使用更少的步骤就可能出错,而不必跟踪诸如您遇到的奇怪问题。在多个进程之间交叉访问文件时应使用锁定。 (你也没有显示'filelock'函数,所以我不知道它是否正确;'fcntl()'锁定有几个问题。) – geekosaur 2011-05-06 21:24:57

+0

@Geekosaur这是我的filelock函数:'int filelock(int fd) {f1} {f1} {f1} {f2} \t fl.l_type = F_WRLCK;/* F_RDLCK,F_WRLCK(独占写锁)或F_UNLCK(解锁区域)*/ \t fl.l_start = 0;/*相对于l_whence的字节偏移量/\t fl.l_whence = SEEK_SET;/* SEEK_SET,SEEK _CUR,SEEK _END */ \t fl.l_len = 0;/*表示锁EOF */ \t \t/* fcntl函数可以改变文件已经打开 \t的性质*这里F_SETLK设置记录锁在羊群结构VAR定义 \t */ \t回报(的fcntl( fd,F_SETLK,&fl)); }' – 2011-05-06 21:26:41