flock():删除没有竞争条件的锁定文件?

Arn*_*anc 21 c flock

我正在将flock()用于进程间命名的互斥锁(即某些进程可以决定对"some_name"进行锁定,这是通过在temp目录中锁定名为"some_name"的文件来实现的:

lockfile = "/tmp/some_name.lock";
fd = open(lockfile, O_CREAT);
flock(fd, LOCK_EX);

do_something();

unlink(lockfile);
flock(fd, LOCK_UN);
Run Code Online (Sandbox Code Playgroud)

应该在某个时候删除锁定文件,以避免使用数百个文件填充临时目录.

但是,此代码中存在明显的竞争条件; 进程A,B和C的示例:

A opens file
A locks file
B opens file
A unlinks file
A unlocks file
B locks file (B holds a lock on the deleted file)
C opens file (a new file one is created)
C locks file (two processes hold the same named mutex !)
Run Code Online (Sandbox Code Playgroud)

有没有办法在某些时候删除锁定文件而不引入这种竞争条件?

use*_*258 24

对不起,如果我回答一个死的问题:

锁定文件后,打开它的另一个副本,fstat两个副本并检查inode编号,如下所示:

lockfile = "/tmp/some_name.lock";

    while(1) {
        fd = open(lockfile, O_CREAT);
        flock(fd, LOCK_EX);

        fstat(fd, &st0);
        stat(lockfile, &st1);
        if(st0.st_ino == st1.st_ino) break;

        close(fd);
    }

    do_something();

    unlink(lockfile);
    flock(fd, LOCK_UN);
Run Code Online (Sandbox Code Playgroud)

这可以防止竞争条件,因为如果程序持有对仍在文件系统上的文件的锁定,则具有剩余文件的每个其他程序将具有错误的inode编号.

我实际上在状态机模型中证明了它,使用以下属性:

如果P_i在文件系统上锁定了描述符,则临界区中没有其他进程.

如果P_i在具有正确inode的stat之后或在临界区中,则它将描述符锁定在文件系统上.

  • 解锁并关闭后,您可以解锁文件吗?手册说flock"在fd指定的打开文件上应用或删除一个咨询锁". (2认同)
  • 您不应该在最后也关闭fd以防止泄漏吗? (2认同)
  • 不便携!例如在 Windows 上,`st_ino` 总是 0。 (2认同)
  • 什么是状态机模型? (2认同)

Gui*_*eim 8

  1. 在 Unix 中,可以在打开文件时将其删除 - inode 将被保留,直到所有进程结束并将其包含在其文件描述符列表中
  2. 在 Unix 中,可以通过检查链接计数(当它变为零时)来检查文件是否已从所有目录中删除

因此,您可以简单地检查已打开文件的 nlink 计数,而不是比较旧/新文件路径的 ino 值。它假定它只是一个临时锁定文件,而不是真正的互斥锁资源或设备。

lockfile = "/tmp/some_name.lock";

for(int attempt; attempt < timeout; ++attempt) {
    int fd = open(lockfile, O_CREAT, 0444);
    int done = flock(fd, LOCK_EX | LOCK_NB);
    if (done != 0) { 
        close(fd);
        sleep(1);     // lock held by another proc
        continue;
    }
    struct stat st0;
    fstat(fd, &st0);
    if(st0.st_nlink == 0) {
       close(fd);     // lockfile deleted, create a new one
       continue;
    }
    do_something();
    unlink(lockfile); // nlink :=0 before releasing the lock
    flock(fd, LOCK_UN);
    close(fd);        // release the ino if no other proc 
    return true;
}
return false;
Run Code Online (Sandbox Code Playgroud)