How to Design Multithreaded Applications to Avoid Deadlock

Last reviewed: September 25, 1995
Article ID: Q126768
The information in this article applies to:
  • Microsoft Win32 Application Programming Interface (API) included with:

        - Microsoft Windows NT versions 3.5 and 3.51
        - Microsoft Windows 95 version 4.0
    

SUMMARY

Debugging a multithreaded application that deadlocks is challenging because the debugger cannot identify for you which thread owns which resource. You would have to track this information in your code. Because it is difficult to debug a deadlock situation, it is important to design your application to avoid deadlock.

This article is a brief introduction to a very complex topic. There are references at the bottom of this article for additional information.

The key point to keep in mind when designing a multithreaded program is that resources must always be requested in the same order.

MORE INFORMATION

The Win32 API provides WaitForSingleObject() and WaitForMultipleObjects() for requesting resources with handles. You would use a different method to request other resources, depending on the resource type.

Many deadlocks occur because resources are not requested in the same order by the application threads. For example:

  • Thread 1 holds resource A and wants resource B.
  • Thread 2 holds resource B and wants resource A.

Both threads block forever, resulting in deadlock. There are many other possible scenarios.

To avoid this problem, identify all of your application's critical resources and order them from least precious to most precious. Design your code such that if a thread needs several resources, it requests them in order, starting with the least precious resource. Resources should be freed in the reverse order and as soon as it is possible. This is not a requirement to avoid deadlock, but it is good practice.

In the example given above, suppose that resource B is more precious than resource A. Here's how the code would resolve the situation:

  • Thread 2 already holds B, but because it wants A, it releases B and waits for A.
  • Thread 1 grabs B, then begins the task. It releases A when possible.
  • Thread 2 grabs A and waits for B.
  • Thread 1 finishes the task, then releases B.
  • Thread 2 grabs B, finishes the task, then releases A, then releases B.

The reason you should request the least precious resource first is that it doesn't matter as much if you hold it longer while waiting to acquire all the resources that you need. If the resource is precious, you want to hold it for the smallest amount of time possible, so other threads can use it.

REFERENCES

MSDN Development Library, "Detecting Deadlocks in Multithreaded Win32 Applications", by Ruediger Asche.

For more information, refer to a good book on operating system design.


Additional reference words: 3.50 4.00 95 race condition
KBCategory: kbprg
KBSubcategory: BseProcThrd


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: September 25, 1995
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.