Threads output/execution question

Hi,

I have a ruby multi-threaded application and I don't understand its
behaviour. I hate just dumping code in a post and asking questions,
but I cannot explain the problem otherwise. In the code below, I have
a loop which requests user input to either start/stop a job. The
execution of the job will happen in a separate thread, because the job
can terminate unexpectedly. What I don't understand in the code, is
why doesn't the application just print "Job.start" and
"'DummyThreads.start" after 5 seconds in the same standard output
screen (as where it is receiving input). It is not even about the
screen (I tried putting STDOUT.flush after every puts statement), the
code is not even executed until I subsequently call DummyThreads
again.

So, what I get is:
Enter option: 1
[...more than 5 seconds passed...]
Enter option: 1
[...immediately...]
Job.start
DummyThreads.start
Enter option:
[...]

What I expected is:
Enter option: 1
Enter option:
[...after 5 seconds...]
Job.start
DummyThreads.start
[...]

Thanks,
Tiberiu

PS. here is my code

class Job
  def run
    sleep 5
    puts 'Job.start'
  end
  def kill
    sleep 5
    puts 'Job.stop'
  end
end

class DummyThreads
  def initialize
    @job = Job.new
  end
  def start
    t = Thread.new { @job.run; puts 'DummyThreads.start' }
    t.join
  end
  def stop
    t = Thread.new { @job.kill; puts 'DummyThreads.stop' }
    t.join
  end
end

# create DummyThreads
dummythreads = DummyThreads.new

# get user input
puts 'Enter option: '
STDOUT.flush
while option = gets
  case option.to_i
    when 1: t = Thread.new { dummythreads.start }
    when 2: t = Thread.new { dummythreads.stop }
    when 0: break
  end
  puts 'Enter option: '
  STDOUT.flush
end

IMHO you have too many threads in there. Try this for an alternative:

  robert

class Job
   class JobTermination < Exception; end

   def run
     @thread = Thread.current
     begin
       puts 'Job.start'
       work
       puts 'Job.finish'
     rescue JobTermination
       puts 'Job.killed'
     ensure
       @thread = nil
     end
   end
   def kill
     puts 'Job.stop'
     @thread.raise JobTermination if @thread
   end

   private
   def work
     sleep 5
   end
end

class DummyThreads
   def initialize
     @job = Job.new
   end
   def start
     puts 'DummyThreads.start'
     Thread.new { @job.run }
   end
   def stop
     @job.kill
     puts 'DummyThreads.stop'
   end
end

# create DummyThreads
dummythreads = DummyThreads.new

# get user input
puts 'Enter option: '
STDOUT.flush
while option = gets
   case option.to_i
     when 1: dummythreads.start
     when 2: dummythreads.stop
     when 0: break
   end
   puts 'Enter option: '
   STDOUT.flush
end

···

On 08.05.2007 04:14, tiberiu.motoc@gmail.com wrote:

Hi,

I have a ruby multi-threaded application and I don't understand its
behaviour. I hate just dumping code in a post and asking questions,
but I cannot explain the problem otherwise. In the code below, I have
a loop which requests user input to either start/stop a job. The
execution of the job will happen in a separate thread, because the job
can terminate unexpectedly. What I don't understand in the code, is
why doesn't the application just print "Job.start" and
"'DummyThreads.start" after 5 seconds in the same standard output
screen (as where it is receiving input). It is not even about the
screen (I tried putting STDOUT.flush after every puts statement), the
code is not even executed until I subsequently call DummyThreads
again.

So, what I get is:
Enter option: 1
[...more than 5 seconds passed...]
Enter option: 1
[...immediately...]
Job.start
DummyThreads.start
Enter option:
[...]

What I expected is:
Enter option: 1
Enter option:
[...after 5 seconds...]
Job.start
DummyThreads.start
[...]

Thanks,
Tiberiu

PS. here is my code

class Job
  def run
    sleep 5
    puts 'Job.start'
  end
  def kill
    sleep 5
    puts 'Job.stop'
  end
end

class DummyThreads
  def initialize
    @job = Job.new
  end
  def start
    t = Thread.new { @job.run; puts 'DummyThreads.start' }
    t.join
  end
  def stop
    t = Thread.new { @job.kill; puts 'DummyThreads.stop' }
    t.join
  end
end

# create DummyThreads
dummythreads = DummyThreads.new

# get user input
puts 'Enter option: '
STDOUT.flush
while option = gets
  case option.to_i
    when 1: t = Thread.new { dummythreads.start }
    when 2: t = Thread.new { dummythreads.stop }
    when 0: break
  end
  puts 'Enter option: '
  STDOUT.flush
end

Hi Robert,

Thanks so much for your answer. Actually even with your code I had the
same problem. If I would wait for more than 5 seconds, the worker
thread would not print "Job.finish" (Job.finish would be printed after
my subsequent input). I realized in both cases that the line "while
option = gets" was blocking the thread from outputing.

Tiberiu