2011-05-06 100 views
1

我的代碼,以守護進程的過程是:如何確保只有一個守護進程正在運行?

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

回答

2

請勿使用文件鎖定;相反,使用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

相關問題