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 times and each
repetition separated by 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
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
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
Vincent F. 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
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 times and each
repetition separated by 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.
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
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 F. wrote:
Sorry for sending three messages, my ?!#$ SMTP server refused to
deliver two messages, but actually did deliver them half an hour later.
Vince
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
[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
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.
Sylvain J. 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.