class Coroutine def initialize(data = {}) @data = data callcc do |@continue| return end yield self end attr_reader :stopped def run callcc do |@stopped| continue end end def stop @stopped.call end def resume(other) callcc do |@continue| other.continue(self) end end def continue(from = nil) @stopped = from.stopped if not @stopped and from @continue.call end def [](name) @data[name] end def []=(name, value) @data[name] = value end protected :stopped, :continue end
count = (ARGV.shift || 1000).to_i input = (1..count).map { (rand * 10000).round.to_f / 100} Producer = Coroutine.new do |me| loop do 1.upto(6) do me[:last_input] = input.shift me.resume(Printer) end input.shift # discard every seventh input number end end Printer = Coroutine.new do |me| loop do 1.upto(8) do me.resume(Producer) if Producer[:last_input] print Producer[:last_input], "\t" Producer[:last_input] = nil end me.resume(Controller) end puts end end Controller = Coroutine.new do |me| until input.empty? do me.resume(Printer) end end Controller.run puts