Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |
To drive a Runnable object with a thread, you create
a separate Thread object and hand a Runnable pointer to the Thread s
constructor. This performs the thread initialization and then calls the Runnable s
run( ) as an interruptible thread. By driving LiftOff with a Thread,
the example below shows how any task can be run in the context of another
thread:
//: C11:BasicThreads.cpp
// The most basic use of the Thread class.
//{L} ZThread
#include <iostream>
#include "LiftOff.h"
#include "zthread/Thread.h"
using namespace ZThread;
using namespace std;
int main() {
try {
Thread t(new LiftOff(10));
cout << "Waiting for LiftOff"
<< endl;
} catch(Synchronization_Exception& e) {
cerr << e.what() << endl;
}
} ///:~
Synchronization_Exception is part of the ZThread library and is the base class for all ZThread exceptions. It will be
thrown if there is an error starting or using a thread.
A Thread constructor only needs a pointer to a Runnable
object. Creating a Thread object will perform the necessary
initialization for the thread and then call that Runnable s run( )
member function to start the task. Even though the Thread constructor
is, in effect, making a call to a long-running function, that constructor
quickly returns. In effect, you have made a member function call to LiftOff::run( ),
and that function has not yet finished, but because LiftOff::run( ) is
being executed by a different thread, you can still perform other operations in
the main( ) thread. (This ability is not restricted to the main( )
thread any thread can start another thread.) You can see this by running the
program. Even though LiftOff::run( ) has been called, the Waiting
for LiftOff message will appear before the countdown has completed. Thus, the
program is running two functions at once LiftOff::run( ) and main( ).
You can easily add more threads to drive more tasks. Here,
you can see how all the threads run in concert with one another:
//: C11:MoreBasicThreads.cpp
// Adding more threads.
//{L} ZThread
#include <iostream>
#include "LiftOff.h"
#include "zthread/Thread.h"
using namespace ZThread;
using namespace std;
int main() {
const int SZ = 5;
try {
for(int i = 0; i < SZ; i++)
Thread t(new LiftOff(10, i));
cout << "Waiting for LiftOff"
<< endl;
} catch(Synchronization_Exception& e) {
cerr << e.what() << endl;
}
} ///:~
The second argument for the LiftOff constructor
identifies each task. When you run the program, you ll see that the execution
of the different tasks is mixed together as the threads are swapped in and out.
This swapping is automatically controlled by the thread scheduler. If you have
multiple processors on your machine, the thread scheduler will quietly
distribute the threads among the processors.
The for loop can seem a little strange at first
because t is being created locally inside the for loop and then
immediately goes out of scope and is destroyed. This makes it appear that the thread
itself might be immediately lost, but you can see from the output that the
threads are indeed running to conclusion. When you create a Thread
object, the associated thread is registered with the threading system, which
keeps it alive. Even though the stack-based Thread object is lost, the
thread itself lives on until its associated task completes. Although this may
be counterintuitive from a C++ standpoint, the concept of threads is a
departure from the norm: a thread creates a separate thread of execution that
persists after the function call ends. This departure is reflected in the
persistence of the underlying thread after the object vanishes.
Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |