如何使用try语句避免竞争条件?

Hon*_*Abe 26 python race-condition

在确定文件是否存在时,如何使用try语句避免"竞争条件"?

我问,因为一个高度赞成的答案(更新:它被删除)似乎意味着使用os.path.exists()创造了一个不存在的机会.

给出的例子是:

try:
   with open(filename): pass
except IOError:
   print 'Oh dear.'
Run Code Online (Sandbox Code Playgroud)

但我不明白如何避免竞争条件相比:

if not os.path.exists(filename):
    print 'Oh dear.'
Run Code Online (Sandbox Code Playgroud)

如何调用os.path.exists(filename)允许攻击者对他们不能做的文件做些什么?

Ell*_*ioh 32

当然,竞争条件是在您的程序和其他一些在文件上运行的代码之间(竞争条件总是需要至少两个并行进程或线程,详情请参阅内容).这意味着使用open()而不是exists()仅仅在两种情况下可以帮助:

  1. 您检查是否存在由某个后台进程创建或删除的文件(但是,如果您在Web服务器内运行,这通常意味着您的进程有许多副本并行运行以处理HTTP请求,因此对于Web应用程序竞争条件是可能的,即使没有其他程序).
  2. 可能有一些恶意程序正在尝试通过在您希望它存在的时刻销毁文件来破坏您的代码.

exists()只需执行一次检查.如果文件存在,则exists()返回后可能会删除一微秒True.如果文件不存在,可以立即创建.

但是,open()不仅测试文件存在,而且还打开文件(并以原子方式执行这两个操作,因此在检查和开放之间不会发生任何事情).通常,文件在某人打开时无法删除.这意味着with你内心可能完全确定:文件现在确实存在,因为它是开放的.虽然它只在内部with,但是在with块退出后仍然可以立即删除文件,将需要文件的代码放在内部可以with保证代码不会失败.


Ran*_*ook 9

这是一个用法示例:

try:
    with open('filename') as f:
        do_stuff_that_depends_on_the_existence_of_the_file(f)
except IOError as e:
    print 'Trouble opening file'
Run Code Online (Sandbox Code Playgroud)

如果您打开任何访问权限的文件,那么操作系统将保证该文件存在,否则它将失败并显示错误.如果访问权限是独占的,则任何其他争用文件的进程都将被您阻止,或阻止您.

try只是一种检测打开文件的错误或成功的方法,因为Python中的文件I/O API通常没有返回代码(而是使用异常).所以要真正回答你的问题,那不是try避免竞争条件,而是它open.它在C(Python所基于的)中基本相同,但没有例外.阅读本文以获取更多信息.

请注意,您可能希望执行依赖于对try块内文件的访问的代码.关闭文件后,不再保证其存在.

调用os.path.exists仅在文件可能存在或不存在的时刻给出快照,并且一旦os.path.exists返回就不知道文件是否存在.恶意代码或意外逻辑可能会在您不期望时删除或更改文件.它类似于在开车前检查道路是否清晰.一旦你转过头来,你只能猜测你不再寻找的地方.保持文件打开可确保延长的一致状态,这在驾驶时是不可能的(无论好坏).:)

try/open由于快照性质的原因,您建议检查文件是否存在而不是使用仍然是不够的os.path.exists.不幸的是,我知道在所有情况下都无法阻止在目录中创建文件,因此我认为最好检查文件是否存在,而不是缺少文件.