4.18.3. Kooperující procedury
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