如何确保只有一个守护进程正在运行?
我的代码,以守护进程的过程是:如何确保只有一个守护进程正在运行?
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
但每当这个命令执行两个或更多时候,它会在运行状况下创建相同数量的守护进程。我想摆脱这种行为。任何建议将不胜感激。
请勿使用文件锁定;相反,使用O_EXCL
标志open()
,如果该文件已存在,则该标志将失败,并显示EEXIST
。这通常是用pid文件完成的,因为它无论如何都需要是独占的。
@geekosaur但是在带有fcntl函数的filelock()中,我正在以独占写锁的F_WRLCK模式打开pid文件。所以这应该与open()中的O_EXCL模式相同。 – 2011-05-06 21:19:05
@Sushant:这可能是,但它更难做到(因此更容易出错和竞争条件)。一般来说,我更喜欢更简单的方法,使用更少的步骤就可能出错,而不必跟踪诸如您遇到的奇怪问题。在多个进程之间交叉访问文件时应使用锁定。 (你也没有显示'filelock'函数,所以我不知道它是否正确;'fcntl()'锁定有几个问题。) – geekosaur 2011-05-06 21:24:57
@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
阅读[这个答案](http://stackoverflow.com/questions/688343/reference-for-proper-handling-of-pid-file-on-unix),并要非常小心的竞态条件和错误。 – Emmet 2014-04-03 17:51:50