Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |
The goal of this chapter was to give you the foundations of
concurrent programming with threads:
1. You
can run multiple independent tasks.
2. You
must consider all the possible problems when these tasks shut down. Objects or
other tasks may disappear before tasks are finished with them.
3. Tasks
can collide with each other over shared resources. The mutex is the basic tool
used to prevent these collisions.
4. Tasks
can deadlock if they are not carefully designed.
However, there are multiple additional facets of threading
and tools to help you solve threading problems. The ZThreads library contains a
number of these tools, such as semaphores and special types of queues,
similar to the one you saw in this chapter. Explore that library as well as
other resources on threading to gain more in-depth knowledge.
It is vital to learn when to use concurrency and when to avoid it. The main reasons to use it are:
To manage a number of tasks whose intermingling use the computer
more efficiently (including the ability to transparently distribute the tasks
across multiple CPUs).
To allow better code organization.
To be more convenient for the user.
The classic example of resource balancing is to use the CPU
during I/O waits. The classic example of user convenience is to monitor a
stop button during long downloads.
An additional advantage to threads is that they provide
light execution context switches (on the order of 100 instructions) rather
than heavy process context switches (thousands of instructions). Since all
threads in a given process share the same memory space, a light context switch
changes only program execution and local variables. A process change the heavy
context switch must exchange the full memory space.
The main drawbacks to multithreading are:
Slowdown occurs while waiting for shared resources.
Additional CPU overhead is required to manage threads.
Unrewarded complexity arises from poor design decisions.
Opportunities are created for pathologies such as starving,
racing, deadlock, and livelock.
Inconsistencies occur across platforms. When developing the
original material (in Java) for this chapter, we discovered race conditions
that quickly appeared on some computers but wouldn t appear on others. The C++
examples in this chapter behaved differently (but usually acceptably) under
different operating systems. If you develop a program on a computer and things
seem to work right, you might get an unwelcome surprise when you distribute it.
One of the biggest difficulties with threads occurs because
more than one thread might be sharing a resource such as the memory in an
object and you must make sure that multiple threads don t try to read and
change that resource at the same time. This requires judicious use of
synchronization tools, which must be thoroughly understood because they can
quietly introduce deadlock situations.
In addition, there s a certain art to the application of
threads. C++ is designed to allow you to create as many objects as you need to
solve your problem at least in theory. (Creating millions of objects for an
engineering finite-element analysis, for example, might not be practical.) However,
there is usually an upper bound to the number of threads you ll want to create,
because at some number, threads may become balky. This critical point can be
difficult to detect and will often depend on the OS and thread library; it
could be fewer than a hundred or in the thousands. As you often create only a
handful of threads to solve a problem, this is typically not much of a limit;
but in a more general design it becomes a constraint.
Regardless of how simple threading can seem using a
particular language or library, consider it a black art. There s always
something you haven t considered that can bite you when you least expect it.
(For example, note that because the dining philosophers problem can be adjusted
so that deadlock rarely happens, you can get the impression that everything is
OK.) An appropriate quote comes from Guido van Rossum, creator of the Python
programming language:
In any project that is multithreaded,
most bugs will come from threading issues. This is regardless of programming
language it s a deep, as yet un-understood property of threads.
For more advanced discussions of threading, see Parallel
and Distributed Programming Using C++, by Cameron Hughes and Tracey Hughes,
Addison Wesley 2004.
Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |