views:

283

answers:

1

I am running some multi-threaded code that does the following.

  1. On an STA thread, I create a 'worker' thread, and run it.
  2. The STA thread then waits for the worker thread to exit.
  3. The worker thread calls a method on a proxy to an STA COM object on the STA thread, and then exits.

In step 2, I'm using Thread.Join() to wait for the worker thread to exit.

The documentation for Thread.Join() states that it blocks the calling thread until a thread terminates, while continuing to perform standard COM and SendMessage pumping.

However, what happens is the worker thread blocks 'forever' on the COM call. The STA thread never services the COM call, while it is blocked on calling Thread.Join() on the worker thread.

I expected the STA thread to be able to service COM calls while blocked on Thread.Join.

Can anyone explain what might be happening here?


Here's the native callstack for the call to Thread.Join (ran VS in native code debugging mode, so differences may be due to not using WinDbg?):

ntdll.dll!_KiFastSystemCallRet@0()  
ntdll.dll!_ZwWaitForMultipleObjects@20()  + 0xc bytes
kernel32.dll!_WaitForMultipleObjectsEx@20()  - 0x51 bytes 
user32.dll!_RealMsgWaitForMultipleObjectsEx@20()  + 0xd7 bytes 
ole32.dll!CCliModalLoop::BlockFn()  + 0x8c bytes 
ole32.dll!_CoWaitForMultipleHandles@20()  - 0x382a bytes 
mscorwks.dll!NT5WaitRoutine()  + 0x39 bytes 
mscorwks.dll!MsgWaitHelper()  + 0x97 bytes 
mscorwks.dll!Thread::DoAppropriateAptStateWait()  + 0x51ae9 bytes 
mscorwks.dll!Thread::DoAppropriateWaitWorker()  + 0x104 bytes 
mscorwks.dll!Thread::DoAppropriateWait()  + 0x40 bytes 
mscorwks.dll!Thread::JoinEx()  + 0x77 bytes 
mscorwks.dll!ThreadNative::DoJoin()  + 0xa6 bytes 
mscorwks.dll!ThreadNative::Join()  + 0xa8 bytes

Here is the call stack shown in the article, for STA threads that call Thread.Join: It appears to diverge from what I'm seeing on the last call.

ntdll!NtWaitForMultipleObjects+0xa
KERNEL32!WaitForMultipleObjectsEx+0x10b
USER32!RealMsgWaitForMultipleObjectsEx+0x129
USER32!MsgWaitForMultipleObjectsEx+0x46
ole32!CCliModalLoop::BlockFn+0xbb
ole32!CoWaitForMultipleHandles+0x145
mscorwks!NT5WaitRoutine+0x77
mscorwks!MsgWaitHelper+0xed
mscorwks!Thread::DoAppropriateAptStateWait+0x67
mscorwks!Thread::DoAppropriateWaitWorker+0x195
mscorwks!Thread::DoAppropriateWait+0x5c
mscorwks!Thread::JoinEx+0xa5
mscorwks!ThreadNative::DoJoin+0xda
mscorwks!ThreadNative::Join+0xfa

Here's the article's callstack for an MTA thread:

ntdll!NtWaitForMultipleObjects+0xa
KERNEL32!WaitForMultipleObjectsEx+0x10b
mscorwks!WaitForMultipleObjectsEx_SO_TOLERANT+0xc1
mscorwks!Thread::DoAppropriateAptStateWait+0x41
mscorwks!Thread::DoAppropriateWaitWorker+0x195
mscorwks!Thread::DoAppropriateWait+0x5c
mscorwks!Thread::JoinEx+0xa5
mscorwks!ThreadNative::DoJoin+0xda
mscorwks!ThreadNative::Join+0xfa
+1  A: 

Is your worker thread operating in an MTA apartment? A Thread.Join will not perform pumping if the current apartment is an MTA. The documentation on MSDN is misleading in this case because it is standard to not pump in an MTA.

Here is an article on the subject

EDIT Re-read the question a bit and saw that the blocking thread is an STA thread. Leaving up answer as a CW in case it helps people hitting the problem in the fashion described

JaredPar
Thread.Join is being called in the STA thread. The worker is the MTA I think - just whatever is the default. Do your comments still apply?
mackenir
Dang. :) ________
mackenir
Answer upvoted for the indirect link to Chris Brumme article, which may help nonetheless...
mackenir