fcntl如何知道哪个进程持有锁文件?

fcntl how to know which process hold lock file?

我是 fcntl 锁定的新手,并按照此示例使用 c 代码在 linux 中创建示例锁:http://www.informit.com/articles/article.aspx?p=23618&seqNum=4

我想知道我们如何才能打印出哪个进程持有锁文件以及哪个进程正在等待锁。我考虑使用 l_pid 来找出持有锁的进程 ID,但我不确定正确的方法。 打印出哪个进程持有锁的最佳方法是什么?

来自示例代码:

printf ("locking\n");
/* Initialize the flock structure. */
memset (&lock, 0, sizeof(lock));
lock.l_type = F_WRLCK;
/* Place a write lock on the file. */
fcntl (fd, F_SETLKW, &lock);

printf ("locked; hit Enter to unlock... ");

您需要将 fcntl (fd, F_SETLKW, &lock); 更改为:

if (fcntl (fd, F_SETLK, &lock) == -1) {
  printf ("File is locked by pid %i\n", lock.l_pid);
  return 0;
}

F_SETLKW 命令在无法获得锁时阻塞。 F_SETLK 如果无法获得锁,将 return。实际上,在获得 -1 return 值后,代码还应该检查 errno == EACCESSerrno == EAGAIN

man 2 fcntl页面所述,您可以使用F_GETLK获取具有冲突锁的进程ID(如果冲突锁是进程相关锁)。所以,例如,

/* Return 0 if descriptor locked exclusively, positive PID if
   a known process holds a conflicting lock, or -1 if the
   descriptor cannot be locked (and errno has the reason).
*/
static pid_t  lock_exclusively(const int fd)
{
    struct flock  lock;
    int           err = 0;

    if (fd == -1) {
        errno = EINVAL;
        return -1;
    }

    lock.l_type = F_WRLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;
    if (!fcntl(fd, F_SETLK, &lock))
        return 0;

    /* Remember the cause of the failure */
    err = errno;

    lock.l_type = F_WRLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;
    lock.l_pid = 0;
    if (fcntl(fd, F_GETLK, &lock) == 0 && lock.l_pid > 0)
        return lock.l_pid;

    errno = err;
    return -1;
}

请注意 fd 必须打开以进行读写。我建议使用 open(path, O_RDWR | O_NOCTTY)open(path, O_WRONLY | O_NOCTTY)。关闭同一文件的 任何 文件描述符将释放锁。

有些人可能会说在第二次 fcntl() 调用之前重新设置 lock 成员是不必要的,但我宁愿在这里谨慎行事。

至于怎么举报,我直接用

int    fd;
pid_t  p;

fd = open(path, O_RDWR | O_NOCTTY);
if (fd == -1) {
    fprintf(stderr, "%s: Cannot open file: %s.\n",
                    path, strerror(errno));
    exit(EXIT_FAILURE);
}

p = lock_exclusively(fd);
if (p < 0) {
    fprintf(stderr, "%s: Cannot lock file: %s.\n",
                    path, strerror(errno));
    exit(EXIT_FAILURE);
} else
if (p > 0) {
    fprintf(stderr, "%s: File is already locked by process %ld.\n",
                    path, (long)p);
    exit(EXIT_FAILURE);
}

/* fd is now open and exclusive-locked. */

用户总是可以 运行 例如ps -o cmd= -p PID 查看那是什么命令(或者您可以尝试阅读 Linux 中的 /proc/PID/cmdline)。