Pitfalls and Common Mistakes
There are several factors to keep in mind as you develop threaded programs; lack of attention to a few basic principles can result in serious defects, and it is best to avoid the problems in the first place rather than try to find them during testing or debugging.
The essential factor is that the threads execute asynchronously. There is no sequencing unless you create it explicitly. This asynchronous behavior is what makes threads so useful, but, without proper care, serious difficulties can occur.
Here are a few guidelines; there will be more in later chapters.
Make no assumptions about the order in which the parent and child threads execute. It is possible for a child thread to run to completion before the parent returns from CreateThread, or, conversely, the child thread may not run at all for a considerable period of time. On an SMP system, the parent and one or more children may even run concurrently. Ensure that all initialization required by the child is complete before the CreateThread call, or else use thread suspension or some other technique. Failure by the parent to initialize data required by the child is a common cause of "race conditions" wherein the parent "races" the child to initialize data before the child needs it. sortMT illustrates this principle. Be certain that each distinct child has its own data structure passed through the thread function's parameter. Do not assume that one child thread will complete before another (this is another form of race condition). Any thread, at any time, can be preempted, and any thread, at any time, may resume execution. Do not use thread priority as a substitute for explicit synchronization. Do not use reasoning such as "that will hardly ever happen" as an argument that a program is correct. If it can happen, it will, possibly at a very embarrassing moment. Even more so than with single-threaded programs, testing is necessary, but not sufficient, to ensure program correctness. It is common for a program to pass extensive tests despite code defects. There is no substitute for careful design, implementation, and code inspection. Threaded program behavior varies widely with processor speed, number of processors, OS version, and more. Testing on a variety of systems can isolate numerous defects, but the preceding precaution still applies. Be certain that threads have a sufficiently large stack, although the default 1MB will suffice in nearly all cases. Threads should be used only as appropriate. Thus, if there are activities that are naturally concurrent, each such activity can be represented by a thread. If, on the other hand, the activities are naturally sequential, threads only add complexity and performance overhead. Fortunately, correct programs are frequently the simplest and have the most elegant designs. Complexity should be avoided wherever possible.
|
No comments:
Post a Comment