On Mon, Aug 14, 2006 at 12:57:09PM +0900, John Carter wrote:
> On Mon, 14 Aug 2006, Francis Cianfrocca wrote:
> 
> >Don't worry about leaving lock files around. If you really don't like it,
> >put it in /tmp or /dev/shm.
> 
> Sigh! Just seems so...messy.

You can check if the file you got a lock on is the one presently on the FS.
If the lockfile was unlinked, File.stat will fail; if another process created
a file with the same name, the ino will differ. You can detect both situations
and try again:

$ cat lock.rb

def lock(filename)
  dest = nil
  loop do
    dest.close if dest
    dest = File.open(filename, "ab")
    dest.flock(File::LOCK_EX)
    old_stat = dest.stat
    new_stat = File.stat(filename) rescue nil
    break if new_stat and
	     old_stat.dev == new_stat.dev and
	     old_stat.ino == new_stat.ino
  end
  yield
ensure
  File.unlink(filename) rescue nil
  dest.close rescue nil
end

LOCKFILE = "lockfile"

$stdout.sync = true

t = Time.new
fork do
  lock LOCKFILE do
    puts "A"
    p File.exist?(LOCKFILE)
    puts "Sleeping in A"
    sleep 10
  end
end

sleep 1
fork do
  lock LOCKFILE do
    puts "B"
    p File.exist?(LOCKFILE)
    puts "Sleeping in B"
    sleep 10
  end
end

sleep 15

puts "Attempting to get lock in C"
lock LOCKFILE do
  puts "C"
  p File.exist?(LOCKFILE)
end


puts "Total time: #{Time.new - t}"

$ ruby lock.rb
A
true
Sleeping in A
B
true
Sleeping in B
Attempting to get lock in C
C
true
Total time: 20.007932

-- 
Mauricio Fernandez  -   http://eigenclass.org   -  singular Ruby