我正在将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之后或在临界区中,则它将描述符锁定在文件系统上.
因此,您可以简单地检查已打开文件的 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)
| 归档时间: |
|
| 查看次数: |
18694 次 |
| 最近记录: |