#!/usr/bin/env ruby

# Original program idea:
# Write a ruby program that checks the integrity of all my FLAC music files,
# and that makes use of my MacBooks Core Duo CPU. Since Ruby doesn't support
# native threadds, I decided to use the Slave library.
#
# Problem:
# I start 3 Slave servers:
# worker1 and worker2 both query the filename server to get the next filename
# to process.
#
# On Mac OS 10.4.10, ruby 1.8.6 (Locomotive or MacPorts, same problem) the second
# worker server process never starts, it seems to sleep forver, and I don't
# see my programming mistake.
#
# The same problem occurs on Ubuntu Feisty.
#
# However: IF you start the 2nd worker after the first worker completed its
# work, it runs without problem.
#
# And: If you disable the call to the filename server, both workers run 
# in parallel, too, without deadlocking.
#
# So the problem has something to do with both workers trying to access the
# same filename server.
#
# Any ideas?

require 'slave'
require 'monitor'
require 'fastthread'

class FlacTestServer
  
  def processFiles(filenameServer)
    50.times do |i|
      #sleep(0.02)
      #Activate this:
      #puts("PID #{ Process.pid }: Iteration #{ i }")
      #and disable this and both workers will run without worker 2 sleeping forever.
      puts("#{ Process.pid }: #{ filenameServer.nextFilename() }")
    end
  end
end

class FilenameServer
  include MonitorMixin
  
  def initialize()
    super
    @counter = 0
  end

  def nextFilename()
    synchronize do
      # Return some dummy data
      @counter += 1 
      "#{ Process.pid }, #{ @counter }"
    end
  end
end


if $0 == __FILE__
  
  fnServer = Slave.new() { FilenameServer.new() }.object
  
  worker1 = Slave.object({:async => true, :psname => 'Worker1'}) { FlacTestServer.new().processFiles(fnServer) }

  # "Works" if you activate this:
  #worker1.join()
  
  worker2 = Slave.object({:async => true, :psname => 'Worker2'}) { FlacTestServer.new().processFiles(fnServer) }
  
  # If you create the slaves using the following method instead, worker2 sometimes runs, sometimes not
  # and sometimes it runs only a few internal iterations before it sleeps forever / deadlocks...?!?
  # But you can get it to work if you active the sleep call in line 37.
  #ftServer1 = Slave.new() { FlacTestServer.new() }.object()
  #ftServer2 = Slave.new() { FlacTestServer.new() }.object()
  #
  #worker1 = Thread.new() { ftServer1.processFiles(fnServer) }
  #worker2 = Thread.new() { ftServer2.processFiles(fnServer) }
  
  worker1.join()
  puts("Worker 1 terminated.")
  
  #puts("Worker 2 status: #{ worker2.status() }") until worker2.join(0.15)
  worker2.join()
  puts("Worker 2 terminated.")
  
  puts("End main program: #{Process.pid}")
end
