Here’s a problem:
- You have an application that’s hanging permanently or temporarily.
- The hang does not occur in any synchronization code that you have written yourself.
- You are writing a windows forms application, or any kind of application using COM interop.
Let me present an educated guess as to what is happening. Note to people getting here by googling: there are actually many other reasons this might happen in addition to the one I am going to tell you about. I merely suggest that you spend more time thinking before being led too far down a rabbit hole by what I am about to write. Experience has taught me that people tend to lock on to one internet analysis (say, an unrelated KB article mentioning the same exception text) and waste a lot of time on it. None of the other sites seem to be nice enough to explicitly warn you about your own tendencies—I am, you should thank me.
With those disclaimers, here is my psychic debugging response:
- You are inadvertently calling a method on an STA object created on a different thread.
- That other thread is busy doing something else.
For people that managed (har har) to avoid COM development, or stayed completely in the insulated VB6 world, I will now explain briefly everything you really need to know about threading models in this, our fantastic futuristic age.
Methods on single threaded apartment (STA) objects are synchronized. The object receives all calls to its methods on the thread that owns it. This is achieved by creating a hidden window that receives messages for any calls made on those objects. Multi-threaded apartment (MTA) objects behave more or less like any .NET object you create: calls are not automatically synchronized, and you are responsible for doing any synchronization necessary yourself.
So in order for calls to STA objects to work correctly, the thread that owns them has to be free to run its message loop a sufficient percentage of the time. Running a computationally-intensive process on an STA thread is a great way to hang the other threads in your application, if you are careless or ignorant of where the STA calls are.
If you attach with Windbg and dump out the native stacks (~*k), you will probably see threads in calls to WaitOne that got there through functions named things like “SendReceive” above some interop marshalling code if this is indeed your problem. If you are lucky you might see a function called “GetToSTA,” however, the stacks unfortunately do not always make things that easy.
This is one of those things that I have seen a bunch of times, but seems to be on the radar of an increasingly small number of people. It often takes me longer than it should to figure it out, too. If you are doing any kind of practical Windows development, you still need to understand the basics of STA/MTA. That’s because any development that is “practical” will almost necessarily involve interoperating with old code.
Here’s a related post that I wrote, about how STA objects can result in blocked finalizer threads.