In a well-designed application, you'll normally just let threads do
their thing; building timing dependencies into a multithreaded
application is generally considered to be bad form.
However, there are times when you need to control threads. Perhaps the
jukebox has a thread that displays a light show. We might need to stop
it temporarily when the music stops. You might have two threads in a
classic producer-consumer relationship, where the consumer has to
pause if the producer gets backlogged.
Class
Thread
provides a number of methods to control the thread
scheduler. Invoking
Thread.stop
stops the current thread, while
Thread#run
arranges for a particular thread to be
run.
Thread.pass
deschedules the current thread, allowing others
to run, and
Thread#join
and
Thread#value
suspend the
calling thread until a given thread finishes.
We can demonstrate these features in the following, totally pointless
program.
t = Thread.new { sleep .1; Thread.pass; Thread.stop; }
|
t.status
|
� |
"sleep"
|
t.run
|
t.status
|
� |
"run"
|
t.run
|
t.status
|
� |
false
|
However, using these primitives to achieve any kind of real
synchronization is, at best, hit or miss; there will always be race
conditions waiting to bite you. And when you're working with shared
data, race conditions pretty much guarantee long and frustrating
debugging sessions. Fortunately, threads have one additional
facility---the idea of a critical section. Using this, we can build a
number of secure synchronization schemes.