On Aug 19, 2007, at 6:49 PM, Tom Danielsen wrote:
>
> Ok.... this is my first attempt at using callcc in ruby.
Neat idea.
Here's my own version using fork():
#!/usr/bin/env ruby -wKU
unless ARGV.size == 2
abort "Usage: #{File.basename($PROGRAM_NAME)} PROCESSES CYCLES"
end
processes, cycles = ARGV.map { |n| n.to_i }
parent, child = true, false
parent_reader, parent_writer = IO.pipe
reader, writer = IO.pipe
my_reader = parent_reader
puts "Creating #{processes} processes..."
processes.times do |process|
if fork
break
else
parent_reader.close unless parent_reader.closed?
writer.close
parent = false
my_reader = reader
reader, writer = IO.pipe
end
child = true if process == processes - 1
end
if child
puts "Done."
my_writer = parent_writer
else
parent_writer.close
my_writer = writer
end
if parent
puts "Timer started."
start_time = Time.now
puts "Sending a message around the ring #{cycles} times..."
cycles.times do
my_writer.puts "0 Ring message"
my_writer.flush
raise "Failure" unless my_reader.gets =~ /\A#{processes} Ring
message\Z/
end
puts "Done: success."
puts "Time in seconds: #{(Time.now - start_time).to_i}"
else
my_reader.each do |message|
if message =~ /\A(\d+)\s+(.+)/
my_writer.puts "#{$1.to_i + 1} #{$2}"
my_writer.flush
end
end
end
__END__
And here's a threaded attempt:
#!/usr/bin/env ruby -wKU
begin
require "fastthread"
puts "Using the fastthread library."
rescue LoadError
require "thread"
puts "Using the standard Ruby thread library."
end
module MRing
class Forward
def initialize(count, parent)
@child = count.zero? ? parent : Forward.new(count - 1, parent)
@queue = Queue.new
run
end
def send_message(message)
@queue.enq message
end
private
def run
Thread.new do
loop do
message = @queue.deq
if message =~ /\A(\d+)\s+(.+)/
@child.send_message "#{$1.to_i + 1} #{$2}"
end
end
end
end
end
class Parent < Forward
def initialize(processes, cycles)
@processes = processes
@cycles = cycles
puts "Creating #{processes} processes..."
super(processes, self)
end
private
def run
puts "Timer started."
start_time = Time.now
puts "Sending a message around the ring #{@cycles} times..."
@cycles.times do
@child.send_message "0 Ring message"
raise "Failure" unless @queue.deq =~ /\A#{@processes} Ring
message\Z/
end
puts "Done: success."
puts "Time in seconds: #{(Time.now - start_time).to_i}"
end
end
end
if __FILE__ == $PROGRAM_NAME
unless ARGV.size == 2
abort "Usage: #{File.basename($PROGRAM_NAME)} PROCESSES CYCLES"
end
processes, cycles = ARGV.map { |n| n.to_i }
MRing::Parent.new(processes, cycles)
end
__END__
James Edward Gray II