如果一个进程给一个文件一个写锁,然后它生成一个子进程,那么锁是由该子进程继承的吗?如果是的话,那么有2个进程有写锁,我了解到有只有1个进程可以有写锁吗?这是一个测试python代码
#!/usr/bin/python
import fcntl
import time
import os
fp = open('test.ini','w')
fcntl.flock(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
pid = os.fork()
if pid > 0:
time.sleep(10)
exit(0)
if pid == 0:
time.sleep(100)
exit(0)
当父级存在时,我试图获得文件test.ini的锁,但失败,所以我猜子级具有锁
因此,正如您在flock(2)的手册页中所指出的,锁和文件之间的关系如下:
flock()创建的锁与打开的文件描述相关联(请参见open(2))。这意味着重复的文件描述符(例如,由fork(2)或dup(2)创建)引用相同的锁,并且可以使用这些文件描述符中的任何一个来修改或释放该锁。此外,通过对这些重复文件描述符中的任何一个执行显式lock_UN操作,或者当所有这些文件描述符都已关闭时,就会释放锁。
需要明确的是,当锁被释放时,它注意到两种情况:
- 通过对这些重复文件描述符中的任何一个执行显式
LOCK_UN
操作 - 当所有此类文件描述符都已关闭时
在问题中提供的代码中,父执行或子执行都没有明确的解锁,因此第一个条件将不满足。类似地,由于第二个条件要求所有这样的文件描述符都已关闭,因此提前终止父进程不会满足这一要求;只有当子进程稍后终止时。
你可以通过添加一个显式解锁来满足自己这一点:
fcntl.flock(fp, fcntl.LOCK_UN)
在退出之前的父代码路径中,然后在子进程退出之前测试从单独的进程获取锁。这种修改后的代码可以在下面找到:
#!/usr/bin/python
import fcntl
import time
import os
fp = open('test.ini','w')
fcntl.flock(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
pid = os.fork()
if pid > 0:
time.sleep(10)
fcntl.flock(fp, fcntl.LOCK_UN)
exit(0)
if pid == 0:
time.sleep(100)
exit(0)
您还可以读取/proc/locks
或使用lslocks
(相同的解析器)来显示系统中当前持有的文件锁。前者的内容看起来像:
1: FLOCK ADVISORY WRITE 358 00:15:628 0 EOF
2: FLOCK ADVISORY WRITE 296 00:15:608 0 EOF
3: FLOCK ADVISORY WRITE 291 00:15:599 0 EOF
4: FLOCK ADVISORY WRITE 25874 b3:02:256617 0 EOF
后者的输出:
COMMAND PID TYPE SIZE MODE M START END PATH
(unknown) 25874 FLOCK WRITE 0 0 0 /...
cron 291 FLOCK WRITE 0 0 0 /run...
(unknown) 296 FLOCK WRITE 0 0 0 /run...
(unknown) 358 FLOCK WRITE 0 0 0 /run...
当按PID过滤此输出时,要使用的是父PID,除非子PID中的模式已更改。
我认为手册页中的措辞令人困惑:
$ cat lock_assoc.py
#!/usr/bin/python3
import fcntl
f3 = open('test.ini','w')
fcntl.flock(f3, fcntl.LOCK_EX | fcntl.LOCK_NB)
fcntl.flock(f3, fcntl.LOCK_EX | fcntl.LOCK_NB)
f4 = open('test.ini','w')
fcntl.flock(f4, fcntl.LOCK_EX | fcntl.LOCK_NB)
$ strace -f -e flock ./lock_assoc.py
flock(3, LOCK_EX|LOCK_NB) = 0
flock(3, LOCK_EX|LOCK_NB) = 0
flock(4, LOCK_EX|LOCK_NB) = -1 EAGAIN (Resource temporarily unavailable)
Traceback (most recent call last):
File "./lock_assoc.py", line 8, in <module>
fcntl.flock(f4, fcntl.LOCK_EX | fcntl.LOCK_NB)
BlockingIOError: [Errno 11] Resource temporarily unavailable
+++ exited with 1 +++
当手册页上写着:
flock()创建的锁与打开的文件描述相关联〔…〕
这显然意味着锁所有者与打开的文件相关联,而锁本身(可能很明显)与文件索引节点相关联。
这就是为什么如果我使用相同的打开文件(上面的f3
),我可以使用一个已经被独占锁定的锁——这是对表示锁所有者的数据结构的幂等运算。
另一个文件描述符(f4
)具有另一个锁所有者;"我不是主人";,当它试图获得所有权时,它失败了,因为inode知道所有者是f3
。
$ cat lock_fork.py
#!/usr/bin/python3
import fcntl
import time
import os
f3 = open('test.ini','w')
fcntl.flock(f3, fcntl.LOCK_EX | fcntl.LOCK_NB)
f4 = open('test.ini','w')
pid = os.fork()
if pid > 0:
time.sleep(1)
exit(0)
elif pid == 0:
time.sleep(3)
fcntl.flock(f3, fcntl.LOCK_EX | fcntl.LOCK_NB)
fcntl.flock(f4, fcntl.LOCK_EX | fcntl.LOCK_NB)
exit(0)
$ strace -f -e flock ./lock_fork.py
flock(3, LOCK_EX|LOCK_NB) = 0
strace: Process 146372 attached
[pid 146371] +++ exited with 0 +++
flock(3, LOCK_EX|LOCK_NB) = 0
flock(4, LOCK_EX|LOCK_NB) = -1 EAGAIN (Resource temporarily unavailable)
Traceback (most recent call last):
File "./lock_fork.py", line 18, in <module>
fcntl.flock(f4, fcntl.LOCK_EX | fcntl.LOCK_NB)
BlockingIOError: [Errno 11] Resource temporarily unavailable
+++ exited with 1 +++
在这里,我们看到fork()
复制了f3
和f4
,并且即使通过父级死亡,与f3
和f4
相关联的锁所有者数据结构也保留在子级中。子级的f3
仍然可以幂等地再次获取锁,而f4
不能。
文件锁与打开的文件描述符相关联。这意味着,当您将使用类似于dup()的系统调用复制描述符时(或者当子进程将从其父进程继承文件描述符时),锁也将被继承。例如
flock(fd, LOCK_EX);//get a lock
newfd = dup(oldfd);//duplicating the file descriptors
flock(newfd, LOCK_UN);//THis call will release the lock using the duplicated file descriptor.
我希望这些信息能有所帮助。