Python fcntl没有按预期锁定

Ing*_*her 23 python fcntl

在基于Debian的操作系统(Ubuntu,Debian Squeeze)上,我使用Python(2.7,3.2)fcntl来锁定文件.据我所知,fnctl.flock以某种方式锁定文件,如果另一个客户端想要锁定同一个文件,则会抛出异常.

我构建了一个小例子,我希望抛出一个例外,因为我先锁定文件,然后,我立即尝试再次锁定它:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import fcntl
fcntl.flock(open('/tmp/locktest', 'r'), fcntl.LOCK_EX)
try:
    fcntl.flock(open('/tmp/locktest', 'r'), fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    print("can't immediately write-lock the file ($!), blocking ...")
else:
    print("No error")
Run Code Online (Sandbox Code Playgroud)

但该示例只是打印"无错误".

如果我将此代码分割为两个同时运行的客户端(一个锁定然后等待,另一个在第一个锁已经激活后尝试锁定),我得到相同的行为 - 完全没有效果.

对这种行为的解释是什么?

编辑:

根据nightcracker的要求进行更改,此版本还会打印"No error",尽管我不希望这样:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import fcntl
import time
fcntl.flock(open('/tmp/locktest', 'w'), fcntl.LOCK_EX | fcntl.LOCK_NB)
try:
    fcntl.flock(open('/tmp/locktest', 'w'), fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    print("can't immediately write-lock the file ($!), blocking ...")
else:
    print("No error")
Run Code Online (Sandbox Code Playgroud)

phi*_*ilh 15

旧帖子,但如果有人发现它,我会得到这样的行为:

>>> fcntl.flock(open('test.flock', 'w'), fcntl.LOCK_EX)
>>> fcntl.flock(open('test.flock', 'w'), fcntl.LOCK_EX | fcntl.LOCK_NB)
# That didn't throw an exception

>>> f = open('test.flock', 'w')
>>> fcntl.flock(f, fcntl.LOCK_EX)
>>> fcntl.flock(open('test.flock', 'w'), fcntl.LOCK_EX | fcntl.LOCK_NB)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 35] Resource temporarily unavailable
>>> f.close()
>>> fcntl.flock(open('test.flock', 'w'), fcntl.LOCK_EX | fcntl.LOCK_NB)
# No exception
Run Code Online (Sandbox Code Playgroud)

看起来在第一种情况下,文件在第一行之后关闭,可能是因为文件对象不可访问.关闭文件会释放锁定.

  • 请注意,由于 fcntl 模块中的 python 3.3 操作引发 OSError 而不是 IOError (2认同)

小智 14

我讨厌同样的问题...我已经解决了将打开的文件保存在一个单独的变量中:

不会工作:

fcntl.lockf(open('/tmp/locktest', 'w'), fcntl.LOCK_EX | fcntl.LOCK_NB)
Run Code Online (Sandbox Code Playgroud)

作品:

lockfile = open('/tmp/locktest', 'w')
fcntl.lockf(lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
Run Code Online (Sandbox Code Playgroud)

我认为第一个不起作用,因为打开的文件是垃圾收集,关闭锁定释放.

  • 请注意,您使用的是"lockf",而OP在原帖中使用了"flock".这两个是非常不同的实现!名字不好,难以捕捉;) (4认同)

Ing*_*her 11

得到它了.我的脚本中的错误是我在每次调用时创建一个新的文件描述符:

fcntl.flock(open('/tmp/locktest', 'r'), fcntl.LOCK_EX | fcntl.LOCK_NB)
(...)
fcntl.flock(open('/tmp/locktest', 'r'), fcntl.LOCK_EX | fcntl.LOCK_NB)
Run Code Online (Sandbox Code Playgroud)

相反,我必须将文件对象分配给变量,而不是尝试锁定:

f = open('/tmp/locktest', 'r')
fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
(...)
fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
Run Code Online (Sandbox Code Playgroud)

我也得到了我想看到的例外:IOError: [Errno 11] Resource temporarily unavailable.现在我必须考虑在哪些情况下使用fcntl是有意义的.

  • 为了清楚起见,错误不是你在每次调用时都创建一个*new*文件描述符,而是*previous*文件描述符已被垃圾收集(并且之前的锁与它一起).如果要将这两个文件描述符保存到不同的变量,脚本将起作用. (20认同)
  • 这个答案具有误导性。@Dustin 的上述评论是正确的。 (2认同)

orl*_*rlp 6

有两个渔获量.根据文件:

  1. 当操作是LOCK_SH或时LOCK_EX,它也可以按位OR运算LOCK_NB以避免阻塞锁定获取.如果LOCK_NB使用并且无法获取锁定,IOError则会引发一个异常,并将异常errno设置为EACCESEAGAIN(取决于操作系统;为了便携性,请检查两个值).

    你忘了设置LOCK_NB.

  2. 至少在某些系统上,LOCK_EX只有在文件描述符引用为写入而打开的文件时才能使用.

    您打开了一个可供阅读的文件,这可能不支持LOCK_EX您的系统.