如何使用 File#flock 发出非阻塞独占锁请求?

2024-04-26

如何申请非阻塞锁?

为什么 Ruby 没有文件#flock http://www.ruby-doc.org/core-2.0/File.html#method-i-flock当单独尝试锁定文件时是否按预期工作?将文件锁定在块中并不是此问题的正确解决方案,因为重点是显示锁定的行为执着的锁。在块内使用 File#flock 在块退出时会释放锁,因此它不能正确地演示问题。

File#flock 会以多种方式失败,尤其是在请求非阻塞锁时。下面是一些例子。

File#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', File::RDWR|File::CREAT, 0644)
    f2.flock(File::LOCK_EX)
    
  • 当文件被独占锁定时请求非阻塞锁会导致无效参数异常。

    f1 = File.open('foo', File::RDWR|File::CREAT, 0644)
    f1.flock(File::LOCK_EX)
    # => 0
    
    f2 = File.open('foo', File::RDWR|File::CREAT, 0644)
    f2.flock(File::LOCK_NB)
    # => Errno::EINVAL: Invalid argument - foo
    
  • 文档说#flock“根据locking_constant(下表中的值的逻辑或)锁定或解锁文件。”然而,逻辑或引发Errno::EINVAL or Errno::EBADF取决于平台。

    f1 = File.open('foo', File::RDWR|File::CREAT, 0644)
    f1.flock(File::LOCK_EX)
    # => 0
    
    f2 = File.open('foo', File::RDWR|File::CREAT, 0644)
    f2.flock(File::LOCK_NB || File::LOCK_EX)
    # => Errno::EINVAL: Invalid argument - foo
    

首选原生 File#flock 解决方案

虽然人们可能会使用超时模块 http://www.ruby-doc.org/stdlib-2.0/libdoc/timeout/rdoc/Timeout.html募集Timeout::Error当无法获得独占锁时,似乎 File#flock 应该能够本地解决这个问题。那么,实际上应该如何在不阻塞的情况下请求独占锁呢?


使用带有独占锁的超时模块

您可以使用超时模块 http://www.ruby-doc.org/stdlib-2.0/libdoc/timeout/rdoc/Timeout.html设置 #flock 获取排他锁的持续时间。下面的例子将引发Timeout::Error: execution expired,然后可以通过任何适合应用程序的方式对其进行救援。返回nil当计时器到期时,可以测试 #flock 表达式的真实性。

require 'timeout'

f1 = File.open('foo', File::RDWR|File::CREAT, 0644)
f1.flock(File::LOCK_EX)
# => 0

f2 = File.open('foo', File::RDWR|File::CREAT, 0644)
Timeout::timeout(0.001) { f2.flock(File::LOCK_EX) } rescue nil
# => nil

使用按位或进行非阻塞锁定尝试

的文档文件#flock http://www.ruby-doc.org/core-2.0/File.html#method-i-flock says:

根据locking_constant(下表中值的逻辑或)锁定或解锁文件。如果指定了 File::LOCK_NB,则返回 false,否则操作将被阻止。

然而,该方法实际上期望按位或 http://ruby-doc.org/core-2.0/Fixnum.html#method-i-7C运算符,而不是逻辑 OR 关键字在 parse.y 中定义 https://github.com/ruby/ruby/blob/c07d78eb0e8e9d3a8f9e8c860b362964157ff43a/parse.y通过 tOROP 解析器标记。结果,允许 #flock 返回的正确参数false当排它锁失败时实际上是File::LOCK_NB|File::LOCK_EX。例如:

f1 = File.open('foo', File::RDWR|File::CREAT, 0644)
f1.flock(File::LOCK_EX|File::LOCK_NB)
# => 0

f2 = File.open('foo', File::RDWR|File::CREAT, 0644)
f2.flock(File::LOCK_NB|File::LOCK_EX)
# => false

f1.close; f2.close
# => nil

这将在可用时始终生成独占锁;否则,它会立即返回一个假值,而不会产生引发或拯救异常的开销。这显然是该模块的使用方式,但文档可以使用一些说明和附加示例来使其更易于理解。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 File#flock 发出非阻塞独占锁请求? 的相关文章

随机推荐