2

我正在尝试使用锁定文件制作单个实例守护程序,但fcntl()似乎没有按预期工作......

int creat_lock_file (char * pid_fn)
{
  struct flock pid_lck = {F_WRLCK, SEEK_SET,   0,      0,     0 };

  /* Open/Create pid file */
  int pid_fd = open (pid_fn, O_CREAT | O_WRONLY, 0640);
  if (pid_fd == -1)
  {
    syslog (LOG_ERR, "Unable to open PID file > [Errno: %s]",    strerror(errno));
    return -1;
  }

  /* Place write lock on pid file */
  if (fcntl(pid_fd, F_SETLK, &pid_lck) == -1) {
    /* Unhandled error ocured */
    syslog (LOG_ERR, "Unhandled error ocured while locking PID file > [Errno: %s]", strerror(errno));
    close (pid_fd);
    return -1;
  }

  /* Write PID to lock file */
  char pid_lock_buf[11];
  sprintf (pid_lock_buf, "%ld\n", (long) getpid ());
  write (pid_fd, pid_lock_buf, strlen (pid_lock_buf)+1);

  return 0;
}

int get_lock_file_status (char * pid_fn)
{
  struct flock pid_lck = {F_WRLCK, SEEK_SET,   0,      0,     0 };

  /* Open/Create pid file */
  int pid_fd = open (pid_fn, O_CREAT | O_WRONLY, 0640);
  if (pid_fd == -1)
  {
    syslog (LOG_ERR, "Unable to open PID file > [Errno: %s]", strerror(errno));
    return -1;
  }

  /* try locking pid file*/
  if(fcntl(pid_fd, F_GETLK, &pid_lck) == -1)
  {
    if(errno == EAGAIN || errno == EACCES) /* file already locked, close fd and return -1 */
    {
      close (pid_fd);
      return -1;
    }
    else /* Unhandled error ocured */
    {
      syslog (LOG_ERR, "Unhandled error ocured while locking PID file > [Errno: %s]", strerror(errno));
      close (pid_fd);
      return -1;
    }
  }

  close (pid_fd);
  return 0;
}

所以如果它返回-1,我会调用get_lock_file_status并退出,以确保没有其他实例正在运行,而不是我做一些事情(fork chdir 等),并creat_lock_file在成功创建守护进程后调用 crate 并锁定 pid 文件......

当编译并运行程序按预期运行时,运行会创建锁定文件并将 pid 写入其中,但是当第二个实例启动时,第二个实例只是打开相同的锁定文件并将它自己的 pid 写入它!

我究竟做错了什么?第二个实例不应该返回 -1 inget_lock_file_status吗?

4

1 回答 1

1

您正在F_GETLK以错误的方式检查结果。fcntl(2)仅在错误时F_GETLK返回 -1。检查是否可以获得锁的正确方法是检查 的l_type字段struct flock是否设置为F_UNLCK,如下所示:

/* try locking pid file*/
if(fcntl(pid_fd, F_GETLK, &pid_lck) == -1) {
    syslog (LOG_ERR, "Unhandled error ocured while locking PID file > [Errno: %s]", strerror(errno));
    close(pid_fd);
    return -1;
}
close(pid_fd);
return (pid_lck.l_type == F_UNLCK) ? 0 : -1;

应该可以滚动creat_lock_file()get_lock_file_status()进入打开文件的单个函数(如果文件不存在则创建它),尝试对其设置锁定,并返回锁定是否成功(例如,文件描述符或-1)。

truncate(2)顺便说一下,在将 PID 写入其中之前,您应该将 PID 文件设为零字节。假设您的进程的 PID 为 5,PID 文件中的旧 PID 为 123。写入“5”将使 PID 文件的内容为“523”。将文件截断为零字节可以解决这个问题。(O_TRUNC将不起作用,因为您在打开文件以测试是否设置了锁定时会清除文件。)

在程序退出时删除 PID 文件unlink(2)也很常见。这样,文件的不存在表明守护程序没有运行(尽管它不是万无一失的,因为进程或系统可能会崩溃)。

于 2015-03-14T08:35:06.730 回答