为什么Ruby 7 File#flock在单独尝试锁定文件时工作正常?将文件锁定在块中不是解决此问题的正确解决方案,因为重点是显示锁定持久锁的行为.在块中使用File#flock释放锁,当该块退出时,它不会正确显示问题.
File#flock以各种方式失败,特别是在请求非阻塞锁时.一些例子如下.
失败的文件#flock的例子
>使用多个独占锁时,无限等待,因为#flock没有提供超时锁定请求的方法.
# First lock succeeds. f1 = File.open('foo',File::RDWR|File::CREAT,0644) f1.flock(File::LOCK_EX) # => 0 # This never returns. f2 = File.open('foo',0644) f2.flock(File::LOCK_EX)
>当文件被专门锁定时,请求非阻塞锁导致无效的参数异常.
f1 = File.open('foo',0644) f1.flock(File::LOCK_EX) # => 0 f2 = File.open('foo',0644) f2.flock(File::LOCK_NB) # => Errno::EINVAL: Invalid argument - foo
>文档说#flock“根据locked_constant锁定或解锁文件(逻辑或下表中的值)”.但是,逻辑OR会根据平台引发Errno :: EINVAL或Errno :: EBADF.
f1 = File.open('foo',0644) f2.flock(File::LOCK_NB || File::LOCK_EX) # => Errno::EINVAL: Invalid argument - foo
虽然可能使用Timeout module来提高超时::错误时无法获得排他锁,似乎File#flock应该能够本来解决这个问题.那么,一个实际上应该如何请求一个排他锁呢?
解决方法
您可以使用Timeout module设置#flock的持续时间来获取排他锁.以下示例将引发超时::错误:执行过期,然后可以以适用于应用程序的任何方式进行抢救.当定时器到期时返回零,允许#flock表达式被测试为真值.
require 'timeout' f1 = File.open('foo',0644) Timeout::timeout(0.001) { f2.flock(File::LOCK_EX) } rescue nil # => nil
使用按位或进行非阻塞锁定尝试
File#flock的文档说:
Locks or unlocks a file according to locking_constant (a logical or of the values in the table below). Returns false if File::LOCK_NB is specified and the operation would otherwise have blocked.
然而,该方法实际上期望一个Bitwise OR运算符,而不是逻辑OR关键字为defined in parse.y由tOROP解析器令牌.结果,允许#flock在排除锁定失败时返回false的正确参数实际上是File :: LOCK_NB | File :: LOCK_EX.例如:
f1 = File.open('foo',0644) f1.flock(File::LOCK_EX|File::LOCK_NB) # => 0 f2 = File.open('foo',0644) f2.flock(File::LOCK_NB|File::LOCK_EX) # => false f1.close; f2.close # => nil
这可以一直生成排他锁;否则,它立即返回一个伪造值,而不会引发或拯救异常.这显然是模块的使用方式,但文档可以使用一些澄清和其他示例来使其更容易理解.