Signaling another thread

what is is the prefered method in which one thread can ‘signal’ another thread
on some condition? Observable? other?

eg.

other = Thread.new {
do_important_work
}

watch = Thread.new {
loop {
notify(other) if some_test_that_should_interupt_important_work
}
}

one thing i’ve considered doing is something like

worker = Thread.new{stop; do_work}
watcher = Thread.new{stop; loop{check or worker.stop}}

watcher.start
worker.start

perhaps this model would be best done using another process and signals since
the potential for the watcher to be put to sleep at a critical time is larger
with threads…

thoughts?

-a

···

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done
===============================================================================

Ara.T.Howard wrote:

what is is the prefered method in which one thread can ‘signal’ another thread
on some condition? Observable? other?

One way is to use Thread#raise:

$ cat thread-signal.rb
class PayAttention < Exception; end

other = Thread.new do
i=0
begin
loop do
sleep 1
i += 1 # important work
end
rescue PayAttention
puts i
retry if i < 10
end
end

watch = Thread.new do
loop do
sleep 3
other.raise PayAttention
end
end

other.join

$ ruby thread-signal.rb
2
4
6
8
10
$

nice - i’ll take it. thanks.

-a

···

On Thu, 6 May 2004, Joel VanderWerf wrote:

Ara.T.Howard wrote:

what is is the prefered method in which one thread can ‘signal’ another thread
on some condition? Observable? other?

One way is to use Thread#raise:

$ cat thread-signal.rb
class PayAttention < Exception; end

other = Thread.new do
i=0
begin
loop do
sleep 1
i += 1 # important work
end
rescue PayAttention
puts i
retry if i < 10
end
end

watch = Thread.new do
loop do
sleep 3
other.raise PayAttention
end
end

other.join

$ ruby thread-signal.rb
2
4
6
8
10
$

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done
===============================================================================

“Ara.T.Howard” ahoward@fattire.ngdc.noaa.gov schrieb im Newsbeitrag
news:Pine.LNX.4.44.0405051113590.30055-100000@fattire.ngdc.noaa.gov

Ara.T.Howard wrote:

what is is the prefered method in which one thread can ‘signal’
another thread
on some condition? Observable? other?

One way is to use Thread#raise:

$ cat thread-signal.rb
class PayAttention < Exception; end

other = Thread.new do
i=0
begin
loop do
sleep 1
i += 1 # important work
end
rescue PayAttention
puts i
retry if i < 10
end
end

watch = Thread.new do
loop do
sleep 3
other.raise PayAttention
end
end

other.join

$ ruby thread-signal.rb
2
4
6
8
10
$

nice - i’ll take it. thanks.

It depends on the situation: if the thread to notify may be idle, a
ConditionVariable is better.

see:
http://www.ruby-doc.org/docs/rdoc/1.9/classes/ConditionVariable.html

That spares you the sleeping and is the more natural and resource saving
approach.

Regards

robert
···

On Thu, 6 May 2004, Joel VanderWerf wrote:

Robert Klemme wrote:

what is is the prefered method in which one thread can ‘signal’
another thread on some condition? Observable? other?

It depends on the situation: if the thread to notify may be idle, a
ConditionVariable is better.

I’d take the ConditionVariable approach if I could, otherwise I don’t
see why you can’t use the Observer Paradigm. Maybe, I’m missing the point.

Regards,
Ed

···


Edgardo Hames
Consultor Informático
Vates S.A. Ingeniería de Software

ehames@vates.com
Tel: +54 +351 +4240133 int. 121
9 de Julio 228 - 6° piso. Córdoba

“Edgardo Hames” ehames@vates.com schrieb im Newsbeitrag
news:409A9E78.9080702@vates.com

Robert Klemme wrote:

what is is the prefered method in which one thread can ‘signal’
another thread on some condition? Observable? other?

It depends on the situation: if the thread to notify may be idle, a
ConditionVariable is better.

I’d take the ConditionVariable approach if I could, otherwise I don’t
see why you can’t use the Observer Paradigm. Maybe, I’m missing the
point.

Hm, dunno how exactly you want to treat this with observer. But you need
some kind of thread synchronization anyway, even if you use observer.

Are you familiar with multithreaded applications?

Regards

robert

Robert Klemme wrote:

I’d take the ConditionVariable approach if I could, otherwise I don’t
see why you can’t use the Observer Paradigm. Maybe, I’m missing the
point.

Hm, dunno how exactly you want to treat this with observer. But you need
some kind of thread synchronization anyway, even if you use observer.

Are you familiar with multithreaded applications?

Condition variables, semaphores and monitors grant you exclusive access
to shared resources. That means only one thread will access a resource
in a given moment.

The Observer Paradigm, allows an object to be notified when a certain
event happens. Check the following heavily based on the example in “The
Pragmatic Programmer’s Guide” :-). I added a method m to the WarnLow
Class that loops until it gets notified.

I hope it helps.
Ed

----8<--------8<--------8<--------8<----
require “observer”

class Ticker
include Observable
def run
i = 0
while (i < 130)
changed(i > 70)
notify_observers(Time.now, i)
i = i + 1
end
end
end

class Warner
def initialize(ticker, limit)
@limit = limit
ticker.add_observer(self) # all warners are observers
end
end

class WarnLow < Warner
def m
@i = 0
loop do
@i = @i + 1
end
end
def update(time, price) # callback for observer
if price < @limit
print “#@i #{time.to_s}: Price below #@limit: #{price}\n”
end
end
end

class WarnHigh < Warner
def update(time, price) # callback for observer
if price > @limit
print “+++ #{time.to_s}: Price above #@limit: #{price}\n”
end
end
end

ticker = Ticker.new()
Thread.new {
wl = WarnLow.new(ticker, 80)
wl.m
}
WarnHigh.new(ticker, 120)
ticker.run

···


Edgardo Hames
Consultor Informático
Vates S.A. Ingeniería de Software

ehames@vates.com
Tel: +54 +351 +4240133 int. 121
9 de Julio 228 - 6° piso. Córdoba

“Edgardo Hames” ehames@vates.com schrieb im Newsbeitrag
news:409BAC91.4070902@vates.com

Robert Klemme wrote:

I’d take the ConditionVariable approach if I could, otherwise I don’t
see why you can’t use the Observer Paradigm. Maybe, I’m missing the
point.

Hm, dunno how exactly you want to treat this with observer. But you
need
some kind of thread synchronization anyway, even if you use observer.

Are you familiar with multithreaded applications?

Condition variables, semaphores and monitors grant you exclusive access
to shared resources. That means only one thread will access a resource
in a given moment.

The Observer Paradigm, allows an object to be notified when a certain
event happens. Check the following heavily based on the example in “The
Pragmatic Programmer’s Guide” :-). I added a method m to the WarnLow
Class that loops until it gets notified.

That code is not thread safe. At least @i is accessed unsychronized.
While it may work it is unsafe.

Apart from that: all notifications occur in thread main, no thread really
reacts on the status change. Normally you would have used a condition
variable that was accessed from WarnLow#m and #update. Then you would not
have the thread spinning around doing nothing and waisting resources (CPU
cycles that is).

But this seems to be only an example. It depends on the real problem at
hand which approach is best.

Regards

robert
···

I hope it helps.
Ed

----8<--------8<--------8<--------8<----
require “observer”

class Ticker
include Observable
def run
i = 0
while (i < 130)
changed(i > 70)
notify_observers(Time.now, i)
i = i + 1
end
end
end

class Warner
def initialize(ticker, limit)
@limit = limit
ticker.add_observer(self) # all warners are observers
end
end

class WarnLow < Warner
def m
@i = 0
loop do
@i = @i + 1
end
end
def update(time, price) # callback for observer
if price < @limit
print “#@i #{time.to_s}: Price below #@limit: #{price}\n”
end
end
end

class WarnHigh < Warner
def update(time, price) # callback for observer
if price > @limit
print “+++ #{time.to_s}: Price above #@limit: #{price}\n”
end
end
end

ticker = Ticker.new()
Thread.new {
wl = WarnLow.new(ticker, 80)
wl.m
}
WarnHigh.new(ticker, 120)
ticker.run


Edgardo Hames
Consultor Informático
Vates S.A. Ingeniería de Software

ehames@vates.com
Tel: +54 +351 +4240133 int. 121
9 de Julio 228 - 6° piso. Córdoba

Robert Klemme wrote:

That code is not thread safe. At least @i is accessed unsychronized.
While it may work it is unsafe.

I know it is unsafe. I just wanted to write an example on how a thread
could be working and stop when a certain event was notified, which you
cannot do if you where using a Condition Variable. A Condition Variable
could be used to guarantee exclusive access to @i.

Ed

···

----8<--------8<--------8<--------8<----
require “observer”

class Ticker
include Observable
def run
i = 0
while (i < 130)
changed(i > 70)
notify_observers(Time.now, i)
i = i + 1
end
end
end

class Warner
def initialize(ticker, limit)
@limit = limit
ticker.add_observer(self) # all warners are observers
end
end

class WarnLow < Warner
def m
@i = 0
loop do
@i = @i + 1
end
end
def update(time, price) # callback for observer
if price < @limit
print “#@i #{time.to_s}: Price below #@limit: #{price}\n”
end
end
end

class WarnHigh < Warner
def update(time, price) # callback for observer
if price > @limit
print “+++ #{time.to_s}: Price above #@limit: #{price}\n”
end
end
end

ticker = Ticker.new()
Thread.new {
wl = WarnLow.new(ticker, 80)
wl.m
}
WarnHigh.new(ticker, 120)
ticker.run


Edgardo Hames
Consultor Informático
Vates S.A. Ingeniería de Software

ehames@vates.com
Tel: +54 +351 +4240133 int. 121
9 de Julio 228 - 6° piso. Córdoba

“Edgardo Hames” ehames@vates.com schrieb im Newsbeitrag
news:409BD97D.8060805@vates.com

Robert Klemme wrote:

That code is not thread safe. At least @i is accessed unsychronized.
While it may work it is unsafe.

I know it is unsafe. I just wanted to write an example on how a thread
could be working and stop when a certain event was notified,

Your thread does neither stop nor is it interrupted. WarnLow#m just does an
endless loop and increments @i without taking any notice of #update calls.
It is the same instance but a different thread context. You can view that
easily by including the current thread in your printout like

class WarnHigh < Warner
def update(time, price) # callback for observer
if price > @limit
print “#{Thread.current.inspect}: +++ #{time}: Price above #@limit:
#{price}\n”
end
end
end

You’ll notice that it is the same as the main program, which happens to
execute Ticker#run

which you
cannot do if you where using a Condition Variable.

That’s right: with a condition variable the thread is suspended and does
nothing.

A Condition Variable
could be used to guarantee exclusive access to @i.

For exclusive access a mutex is sufficient. The condition variable buys you
the added convenience that a thread is suspended while waiting for a
condition change (technically for a signal to occur).

robert
···

Ed

----8<--------8<--------8<--------8<----
require “observer”

class Ticker
include Observable
def run
i = 0
while (i < 130)
changed(i > 70)
notify_observers(Time.now, i)
i = i + 1
end
end
end

class Warner
def initialize(ticker, limit)
@limit = limit
ticker.add_observer(self) # all warners are observers
end
end

class WarnLow < Warner
def m
@i = 0
loop do
@i = @i + 1
end
end
def update(time, price) # callback for observer
if price < @limit
print “#@i #{time.to_s}: Price below #@limit: #{price}\n”
end
end
end

class WarnHigh < Warner
def update(time, price) # callback for observer
if price > @limit
print “+++ #{time.to_s}: Price above #@limit: #{price}\n”
end
end
end

ticker = Ticker.new()
Thread.new {
wl = WarnLow.new(ticker, 80)
wl.m
}
WarnHigh.new(ticker, 120)
ticker.run


Edgardo Hames
Consultor Informático
Vates S.A. Ingeniería de Software

ehames@vates.com
Tel: +54 +351 +4240133 int. 121
9 de Julio 228 - 6° piso. Córdoba