Multithreading Tips and Tricks

[Previous] [Next]

As I've been emphasizing throughout this book, one of the keys to debugging is up-front planning. With multithreaded programming, up-front planning is the only way you can avoid the dreaded deadlocks. I break down the necessary planning for multithreaded applications into the following categories:

  • Don't do it
  • Multithread only small, discrete pieces
  • Synchronize at the lowest level
  • Review the code—and review the code again
  • Test on multiprocessor machines

Don't Do It

This first tip might seem a little facetious, but I'm absolutely serious. Make sure there's no other way you can structure your program before you decide to incorporate multithreading into your application. When you include multithreading in your application, you're easily adding a minimum of an extra month of development and testing to your schedule.

If you need your program to do some lightweight background processing, check to see whether the work can be handled either through the Microsoft Foundation Class (MFC) library OnIdle processing or through a background periodic timer event. With a little creative thinking, you can probably find a way to avoid multithreading and the headaches that go with it.

Multithread Only Small, Discrete Pieces

If you must multithread, try to keep it to small, discrete pieces. The rule of thumb I use is to not multithread the user interface (UI). Stick to small pieces of work that are generally devoid of any UI elements. For example, printing in the background is a smart use of multithreading because your application's UI will be able to accept input while data is printing.

Synchronize at the Lowest Level

Put your synchronization methods at the lowest level possible in your code. If you need a critical section for protecting a piece of data, put EnterCriticalSection and LeaveCriticalSection around just the actual data access. This placement ensures that you're indeed protecting only the item you're supposed to protect and nothing more. Restricting the scope of your synchronization objects is your best defense against inadvertent deadlocks. One of the nastiest deadlock problems I ever caused was the result of grabbing the synchronization object two functions above where I should have.

Review the Code—and Review the Code Again

If you really do need to multithread your application, you must allow plenty of time to walk through your multithreaded code in full code reviews. The trick is to assign one person to each thread in your code and one person to each synchronization object. In many ways, the code review in multithreaded programming is really a "multithreaded" review.

When you review the code, pretend that each thread is running at real-time priority on its own dedicated CPU. Each "thread person" walks through the code paying attention only to the particular code that his thread is supposed to be executing. When the "thread person" is ready to acquire a synchronization object, the "object person" literally moves behind the "thread person." When the "thread person" releases a synchronization object, the "object person" goes to a neutral corner of the room. In addition to the thread and object representatives, you should have some developers who are monitoring the overall thread activity so that they can assess the program's flow and help determine the points at which different threads deadlock.

As you're working through the code review, keep in mind that the operating system has its own synchronization objects that it applies to your process and that those objects can cause deadlocks as well. The process critical section, explained in the Debugging War Story sidebar "The Deadlock Makes No Sense," and the infamous Microsoft Windows 98 Win16 mutex are both synchronization objects that the operating system uses in your process. Message handling can also cause deadlocks if you're not careful. If thread A is a UI thread and is waiting for a critical section currently owned by thread B, and if thread B sends a message to an HWND in thread A via SendMessage, you'll deadlock. Again, be sure to monitor these activities during your code review.

Test on Multiprocessor Machines

As I mentioned, a multithreaded application requires a much higher level of testing than a single-threaded one. The most important tip I have for testing your multithreaded application is to test it thoroughly on multiprocessor machines. And I don't mean simply running your application through a few paces; I mean continually testing your program in all possible scenarios. Even if your application runs perfectly on single-processor machines, a multiprocessor machine will turn up deadlocks you never thought possible.

The best approach to this kind of testing is to have the team's developers running the application on multiprocessor machines every day. If you're a manager and you don't have any multiprocessor machines in your shop, stop reading right now and immediately equip half your developers and QA testers with multiprocessor machines! If you're a developer without a multiprocessor machine, show this chapter to your manager and demand the proper equipment to do your job!



Debugging Applications
Debugging Applications for MicrosoftВ® .NET and Microsoft WindowsВ® (Pro-Developer)
ISBN: 0735615365
EAN: 2147483647
Year: 2000
Pages: 122
Authors: John Robbins

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net