From: James Edward Gray II Date: 2007-08-20T09:33:04+09:00 Subject: Re: [QUIZ] Process Rings (#135) 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