Suggestion File#lock

rubyists-

due to whacky behavior exhibited on various platforms regarding flock, i would
like to suggest an implementation of a File#lock method similar the following
one. any suggestions to improve it welcome.

file File_lock.rb
----CUT----

File#lock - a method for safely locking a file between processes and/or

threads

class File

require ‘thread’

private
attr_writer :sem

public
attr_reader :sem

def lock
sem = Mutex.new unless sem
sem.synchronize do
catch (:eintr){
begin
loop { flock (LOCK_EX | LOCK_NB) and break or Thread.pass}
rescue Errno::EINTR
throw :eintr
end
}

  yield self

  catch (:eintr){
begin
  flock LOCK_UN
rescue Errno::EINTR
  throw :eintr
end
  }
end

end

end

if $0 == FILE

this program coordinates access to an output file for the purpose of

inserting a timestamp between multiple threads spawned from within multiple

forked processes. the coordination is considered successful if no

timestamps are inserted non-sequentially

require ‘thread’
require ‘ftools’

pid = Process.pid

n_child = (ARGV.shift or 4).to_i
n_thread = (ARGV.shift or 4).to_i
n_mark = (ARGV.shift or 2 << 9).to_i
outpath = (ARGV.shift or ‘/tmp/out’)
sortedpath = (ARGV.shift or ‘/tmp/sorted’)

File.rm_f outpath
File.rm_f sortedpath

n_mark_per_thread = n_mark / n_child / n_thread
cids =

$stdout.sync = true
$stdout.puts “================”
$stdout.puts “N_CHILD : #{n_child}”
$stdout.puts “N_THREAD : #{n_thread}”
$stdout.puts “N_MARK : #{n_mark}”
$stdout.puts “OUTPATH : #{outpath}”
$stdout.puts “================”
$stdout.puts “\n#{pid} STARTED”

n_child.times {
cids <<
Process.fork {
ppid = Process.ppid
pid = Process.pid
sem = Mutex.new
output = “\t#{ppid}.#{pid} STARTED\n”
File.open (outpath, ‘a+’) { |file|
threads =
n_thread.times {
threads <<
Thread.new (threads.size) { |tid|
sem.synchronize {
output << “\t\t#{ppid}.#{pid}.#{tid} STARTED\n”
}
n_mark_per_thread.times {
file.lock { |f|
f.seek IO::SEEK_END
f.syswrite “%10.5f\n” % Time.now.to_f
}
Thread.pass
}
}
}
threads.map {|t| t.join}
}
$stdout.puts output
exit!
}
}

cids.map { |cid| Process.waitpid cid }
cids.map { |cid| $stdout.puts “\t#{pid}.#{cid} FINISHED” }

output = IO.readlines outpath
sorted = output.sort {|a,b| a.to_f <=> b.to_f}

if output != sorted
File.open (sortedpath, ‘w’) {|f| f.puts sorted }
$stdout.puts “\nERROR!”
$stdout.puts “SUGGEST ‘diff -c #{outpath} #{sortedpath}’”
else
$stdout.puts “\nSUCCESS!”
end

end
----CUT----

-a

···

====================================

Ara Howard
NOAA Forecast Systems Laboratory
Information and Technology Services
Data Systems Group
R/FST 325 Broadway
Boulder, CO 80305-3328
Email: ahoward@fsl.noaa.gov
Phone: 303-497-7238
Fax: 303-497-7259
====================================