Threading Question

Discussion in 'Ruby' started by Mike Houghton, Nov 16, 2006.

  1. 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/.
    Mike Houghton, Nov 16, 2006
    #1
    1. Advertising

  2. 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, Nov 16, 2006
    #2
    1. Advertising

  3. 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
    Sylvain Joyeux, Nov 16, 2006
    #3
  4. 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/.
    Stefano Crocco, Nov 16, 2006
    #4
  5. 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, Nov 16, 2006
    #5
  6. Mike Houghton

    Phlip Guest

    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!!!
    Phlip, Nov 16, 2006
    #6
  7. 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, Nov 16, 2006
    #7
  8. 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/.
    Mike Houghton, Nov 16, 2006
    #8
  9. Re: Threading Question -- sorry

    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/
    Vincent Fourmond, Nov 16, 2006
    #9
  10. Re: Threading Question -- sorry

    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/.
    Mike Houghton, Nov 16, 2006
    #10
  11. Re: Threading Question -- sorry

    [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, Nov 16, 2006
    #11
  12. Re: Threading Question -- sorry

    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, Nov 16, 2006
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alina
    Replies:
    0
    Views:
    1,669
    Alina
    Jul 16, 2003
  2. John

    Threading question

    John, Sep 28, 2004, in forum: ASP .Net
    Replies:
    13
    Views:
    627
    =?Utf-8?B?RGF2ZSBCYWNoZXI=?=
    Oct 7, 2004
  3. Replies:
    9
    Views:
    1,010
    Mark Space
    Dec 29, 2007
  4. Steven Woody
    Replies:
    0
    Views:
    394
    Steven Woody
    Jan 9, 2009
  5. Steven Woody
    Replies:
    0
    Views:
    434
    Steven Woody
    Jan 9, 2009
Loading...

Share This Page