Threading Question

Hello,

I'm new (very new!) to Ruby but not to programming. I have a
Thread/class inheritance question.I'm trying to make a simple timer
class that extends Thread and repeats a block <count> times and each
repetition separated by <period> seconds. Here's the code

···

--------------
class Timer < Thread

  def initialize( period, count, &action )

    puts "Begin initialize"
    super
    @period = period
    @count = count
    @action = action
    puts "End initialize"

  end # initialize

  def start

    puts "Begin start"

    1.upto(@count) do
      sleep(@period)
      @action.call

    end

    puts "End start"

  end # start

end #class Timer

threads = []

threads << Timer.new(0.77,3){puts "hi"}

threads.each{ |thr| thr.start}

-------

The output is

Begin initialize
hi
End initialize
Begin start
hi
hi
hi
End start

-------

In my ignorance I expected the supplied block not to be executed in
initialize
and to be executed only in the start method. Please would someone
explain where
I'm going wrong and how to correct it.

Many Thanks

Mike

--
Posted via http://www.ruby-forum.com/.

Hello !

Mike Houghton wrote:

In my ignorance I expected the supplied block not to be executed in
initialize
and to be executed only in the start method. Please would someone
explain where
I'm going wrong and how to correct it.

  First reflex, before posting ;-):

ri Thread.new:

------------------------------------------------------------ Thread::new
     Thread.new([arg]*) {|args| block } => thread

···

------------------------------------------------------------------------
     Creates and runs a new thread to execute the instructions given in
     block. Any arguments passed to Thread::new are passed into the
     block.

        x = Thread.new { sleep 0.1; print "x"; print "y"; print "z" }
        a = Thread.new { print "a"; print "b"; sleep 0.2; print "c" }
        x.join # Let the threads finish before
        a.join # main thread exits...

     produces:

        abxyzc

  So you see, initialize does run the thread. You might want to write an
independent class that would create the thread in the start function.

  Ruby comes with an extensive documentation, at least for standard
classes. I know ri isn't that fast, but faster than any reply here ;-)...

  Welcome to Ruby, and enjoy !

  Vince

--
Vincent Fourmond, PhD student
http://vincent.fourmond.neuf.fr/

If a block is supplied to Thread.new, this block becomes the thread main loop.
Calling super without parents is equivalent in your case to
  super( period, count, &action )

which is basically doing
  Thread.new { puts "hi" }

hence the problem

···

--
Sylvain

Hello !

Mike Houghton wrote:

In my ignorance I expected the supplied block not to be executed in
initialize
and to be executed only in the start method. Please would someone
explain where
I'm going wrong and how to correct it.

  First reflex, before posting ;-):

ri Thread.new:

------------------------------------------------------------ Thread::new
     Thread.new([arg]*) {|args| block } => thread

···

------------------------------------------------------------------------
     Creates and runs a new thread to execute the instructions given in
     block. Any arguments passed to Thread::new are passed into the
     block.

        x = Thread.new { sleep 0.1; print "x"; print "y"; print "z" }
        a = Thread.new { print "a"; print "b"; sleep 0.2; print "c" }
        x.join # Let the threads finish before
        a.join # main thread exits...

     produces:

        abxyzc

  So you see, initialize does run the thread. You might want to write an
independent class that would create the thread in the start function.

  Ruby comes with an extensive documentation, at least for standard
classes. I know ri isn't that fast, but faster than any reply here ;-)...

  Welcome to Ruby, and enjoy !

  Vince

--
Vincent Fourmond, PhD student
http://vincent.fourmond.neuf.fr/

Mike Houghton wrote:

I'm new (very new!) to Ruby but not to programming. I have a
Thread/class inheritance question.I'm trying to make a simple timer
class that extends Thread and repeats a block <count> times and each
repetition separated by <period> seconds. Here's the code

Are you coming from Java? It sets a bad example for threading. Don't use it
just for conveniences

Here's an example how Ruby does thready things without the risk and
complexity of threads in your own code:

require 'timeout'
  status = Timeout::timeout(5) {
    # Something that should be interrupted if it takes too much time...
  }

Look up Timeout, and it might do what you need, or lead to a similar
technique.

···

--
  Phlip
  http://www.greencheese.us/ZeekLand <-- NOT a blog!!!

Hello !

Mike Houghton wrote:

In my ignorance I expected the supplied block not to be executed in
initialize
and to be executed only in the start method. Please would someone
explain where
I'm going wrong and how to correct it.

  First reflex, before posting ;-):

ri Thread.new:

------------------------------------------------------------ Thread::new
     Thread.new([arg]*) {|args| block } => thread

···

------------------------------------------------------------------------
     Creates and runs a new thread to execute the instructions given in
     block. Any arguments passed to Thread::new are passed into the
     block.

        x = Thread.new { sleep 0.1; print "x"; print "y"; print "z" }
        a = Thread.new { print "a"; print "b"; sleep 0.2; print "c" }
        x.join # Let the threads finish before
        a.join # main thread exits...

     produces:

        abxyzc

  So you see, initialize does run the thread. You might want to write an
independent class that would create the thread in the start function.

  Ruby comes with an extensive documentation, at least for standard
classes. I know ri isn't that fast, but faster than any reply here ;-)...

  Welcome to Ruby, and enjoy !

  Vince

--
Vincent Fourmond, PhD student
http://vincent.fourmond.neuf.fr/

Vincent Fourmond wrote:

So you see, initialize does run the thread. You might want to write an
independent class that would create the thread in the start function.

I'm not a thread expert, but I think that something like this should
work

class Timer
  def initialize period, count, &action
    @period=period
    @count=count
    @action=action
   end

   def start
     @count.times do |i|
       t=Thread.new do
         sleep @period
         @action.call
       end
     t.join
     end
   end

end

t=Timer.new( 3, 4){puts "hello"}
t.start

···

--
Posted via http://www.ruby-forum.com/\.

Phlip wrote:

Mike Houghton wrote:

I'm new (very new!) to Ruby but not to programming. I have a
Thread/class inheritance question.I'm trying to make a simple timer
class that extends Thread and repeats a block <count> times and each
repetition separated by <period> seconds. Here's the code

Are you coming from Java? It sets a bad example for threading. Don't use
it
just for conveniences

Here's an example how Ruby does thready things without the risk and
complexity of threads in your own code:

require 'timeout'
  status = Timeout::timeout(5) {
    # Something that should be interrupted if it takes too much time...
  }

Look up Timeout, and it might do what you need, or lead to a similar
technique.

Thanks for the comments.
I looked at Timeout and, though it could be used here, I think its for
something more imperative than running a block every n seconds and
besides the block might
not terminate before the timeout.

···

--
Posted via http://www.ruby-forum.com/\.

Vincent Fourmond wrote:

  Sorry for sending three messages, my ?!#$ SMTP server refused to
deliver two messages, but actually did deliver them half an hour later.

  Vince

···

--
Vincent Fourmond, PhD student
http://vincent.fourmond.neuf.fr/

I tried Vincent's idea of having an independant class and setting the
thread in a start method. i.e.

class Timer

  def initialize( period, count, &action )

    @period = period
    @count = count
    @action = action

  end #initialize

  def start

   Thread.new do
      @count.times do
        @action.call
        #sleep(@period)
      end #do
    end #do

  end #start

end #class Timer

timer = Timer.new( 1,5){puts "x"}
timer.start

This works, but if the sleep(@period) is un-commented it only prints "x"
once. If the sleep line is placed before @action.call then "x" is not
printed at all. I've looked at the documentation for sleep but found no
clues.

Thanks

Mike

···

--
Posted via http://www.ruby-forum.com/.

[previous code snipped]

timer = Timer.new( 1,5){puts "x"}
timer.start

  <= the application finishes here

You have to call #join on your thread or the application finishes and the
thread is killed

Sylvain

Sylvain Joyeux wrote:

[previous code snipped]

timer = Timer.new( 1,5){puts "x"}
timer.start

  <= the application finishes here

You have to call #join on your thread or the application finishes and
the
thread is killed

Sylvain

Yes! Thanks, the light just went on...

class Timer

  def initialize( period, count, &action )

    @period = period
    @count = count
    @action = action

  end #initialize

  def start

   @thr = Thread.new do
      @count.times do
        @action.call
        sleep(@period)
      end #do
    end #do

  end #start

  def join
    @thr.join
  end

end #class Timer

timer = Timer.new( 1,5){puts "x"}
timer.start
timer.join

Ideally what I'd now like to do is make the Timer class such that I
don't need to have a public join method and the @thr.join is, somehow,
called intrinsically.

···

--
Posted via http://www.ruby-forum.com/\.

Mike Houghton wrote:

/ ...

timer = Timer.new( 1,5){puts "x"}
timer.start
timer.join

Ideally what I'd now like to do is make the Timer class such that I
don't need to have a public join method and the @thr.join is, somehow,
called intrinsically.

You do realize, don't you, that if you create a single thread and then join
it, you may as well not have created the thread? Performing a "sleep" call
in the main thread will produce the same result.

···

--
Paul Lutus
http://www.arachnoid.com