ノンブロッキング ロックを要求するにはどうすればよいですか?
ファイルを個別にロックしようとすると、 Ruby のFile#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 (以下の表の値の論理和) に従ってファイルをロックまたはロック解除する」と記載されています。ただし、論理 OR はプラットフォームによっては
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 ソリューションを推奨
排他ロックを取得できない場合はTimeout モジュールを使用して発生させることTimeout::Error
ができますが、File#flock はこの問題をネイティブに解決できるはずです。では、実際にブロックせずに排他ロックを要求するにはどうすればよいのでしょうか?