「ファイルをcloseすればflockも解除される」は嘘
たいていの場合はこのとおりの挙動になるので、これを信じてしまってて、おかげでハマりました。
$ cat a.rb open("test.txt", "r+") do |f| #ファイルをopen f.flock(File::LOCK_EX) #ロックする system("ruby b.rb &") #バックグラウンドでb.rbを実行 end #ファイルを閉じる $ cat b.rb open("test.txt", "r+") do |f| f.flock(File::LOCK_EX) end $ ruby a.rb
これをやると、b.rbは固まります。
open("test.txt", "r+") do |f| f.flock(File::LOCK_EX) system("ruby b.rb &") f.flock(File::LOCK_UN) #アンロック end
としたら、固まらなくなりました。どうも「closeしても、子プロセスが同じファイルを参照しているので、ファイルへの参照が開放されない→ロックが自動解除されない」ということっぽいです。
あ、実際にはファイルになんか書き込んだりするでしょうから、アンロックする前にflushが必要*1ですし、例外が起きた場合にも対応、とか考えると「正しいロック」は
open("test.txt", "r+") do |f| f.flock(File::LOCK_EX) begin … ensure f.flush() #バッファをフラッシュ f.flock(File::LOCK_UN) end end
でしょうか。めんどいな。
ついでですけど、UNIXだと「他のプロセスがロックしてるファイルでも普通に読み書きできちゃう」ってところがWindows(Cygwin含む)と違うんですよね*2。最初びっくりしました。