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
====================================