简体   繁体   English

文件写锁和子进程

[英]file write lock and child process

If a process give a file a write lock and then it spawn a child process, is lock inherited by the child process?如果一个进程给文件一个写锁,然后它产生一个子进程,子进程是否继承锁? If yes, then there is 2 process have the write lock, I learned that there is only 1 process can have a write lock, some truth?如果是,那么有2个进程有写锁,我了解到只有1个进程可以有写锁,有些道理吗? here is a test python code这是一个测试 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)

when the parent exist, i tried to get the lock of file test.ini, but failed , so I guess the child has the lock当父母存在时,我试图获得文件 test.ini 的锁,但失败了,所以我猜孩子有锁

So, as you've noted in the man page for flock(2) , the relationship between the lock and the file is as follows:因此,正如您在flock(2) 的手册页中所述,锁和文件之间的关系如下:

Locks created by flock() are associated with an open file description (see open(2)). flock() 创建的锁与打开的文件描述相关联(请参阅 open(2))。 This means that duplicate file descriptors (created by, for example, fork(2) or dup(2)) refer to the same lock, and this lock may be modified or released using any of these file descriptors.这意味着重复的文件描述符(例如,由 fork(2) 或 dup(2) 创建)引用同一个锁,并且可以使用这些文件描述符中的任何一个来修改或释放此锁。 Furthermore, the lock is released either by an explicit LOCK_UN operation on any of these duplicate file descriptors, or when all such file descriptors have been closed.此外,通过对这些重复文件描述符中的任何一个进行显式 LOCK_UN 操作,或者在所有此类文件描述符都已关闭时,锁定将被释放。

To be clear, it notes two cases when the lock is released:为了清楚起见,它指出了释放锁的两种情况:

  • by an explicit LOCK_UN operation on any of these duplicate file descriptors通过对这些重复文件描述符中的任何一个进行显式LOCK_UN操作
  • when all such file descriptors have been closed当所有此类文件描述符都已关闭时

In the code provided in the question, there is no explicit unlock in either the parent or child execution, so the first condition won't be met.在问题提供的代码中,父级或子级执行中都没有明确解锁,因此不会满足第一个条件。 Similarly, as the second condition requires that all such file descriptors have been closed, this won't be met by the earlier termination of the parent process;类似地,由于第二个条件要求所有此类文件描述符都已关闭,因此较早终止父进程不会满足此条件; only when the child process terminates later.仅当子进程稍后终止时。

You can satisfy yourself that this holds by adding an explicit unlock:您可以通过添加显式解锁来满足自己的要求:

fcntl.flock(fp, fcntl.LOCK_UN)

in the parent code path before the exit, and then test taking the lock from a separate process before the child exits.在退出之前的父代码路径中,然后在子退出之前测试从单独的进程获取锁。 Such modified code can be found below:此类修改后的代码可以在下面找到:

#!/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)

You can also read /proc/locks or use lslocks (a parser of same) to show the currently held file locks in the system.您还可以读取/proc/locks或使用lslocks (相同的解析器)来显示系统中当前持有的文件锁。 The contents of the former look like:前者的内容如下:

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

and the output of the latter:和后者的 output:

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...

When filtering this output by PID the one to use is the parent PID, unless the mode has been changed in the child.当通过 PID 过滤此 output 时,要使用的是父 PID,除非子项中的模式已更改。

File locks are associated with the open file descriptors. 文件锁与打开的文件描述符关联。 This means that when you will duplicate your descriptor with dup() like system call (or when the child process will inherit the file descriptor from its parent), the locks are also inherited. 这意味着当您像系统调用一样使用dup()复制描述符时(或者子进程将从其父进程继承文件描述符时),锁也将被继承。 For example 例如

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.

I hope this info helps. 希望此信息对您有所帮助。

I think the phrasing in the man page is confusing:我认为手册页中的措辞令人困惑:

$ 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 +++

When the man page says:当手册页说:

Locks created by flock() are associated with an open file description [...]由flock() 创建的锁与打开的文件描述相关联[...]

What it apparently means is that the lock owner is associated with the open file, whereas the lock itself is (presumably obviously) associated with the file inode.这显然意味着锁所有者与打开的文件相关联,而锁本身(可能很明显)与文件 inode 相关联。

That's why I can take a lock that's already exclusively locked, if I'm using the same open file ( f3 above) - it's an idempotent operation on the data structure that represents the lock owner.这就是为什么我可以使用已经被独占锁定的锁,如果我使用相同的打开文件(上面的f3 ) - 这是对代表锁所有者的数据结构的幂等操作。

The other file descriptor ( f4 ) has another lock owner, which has the value "I'm not the owner", and when it tries to take ownership, it fails, because the inode knows the owner is 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 +++

Here we see that fork() duplicates both f3 and f4 , and even through the parent dies, the lock owner data structures associated with f3 and f4 remain in the child.在这里,我们看到fork()复制了f3f4 ,即使父级死亡,与f3f4关联的锁所有者数据结构仍保留在子级中。 The child's f3 can still idempotently take the lock again, wherewas f4 cannot.孩子的f3仍然可以再次幂等地取锁,而f4不能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM