为什么 Thread.Join 不让 COM 消息通过?

发布于 2024-08-02 17:43:37 字数 2545 浏览 2 评论 0原文

我正在运行一些执行以下操作的多线程代码。

  1. 在 STA 线程上,我创建了一个 “worker”线程,然后运行它。
  2. 然后STA线程等待worker 线程退出。
  3. 工作线程调用 STA COM 代理上的方法 STA 线程上的对象,然后退出。

在步骤 2 中,我使用 Thread.Join() 等待工作线程退出。

Thread.Join() 的文档指出,它阻塞调用线程直到线程终止,同时继续执行标准 COM 和 SendMessage 泵送

然而,发生的情况是工作线程“永远”阻塞 COM 调用。 STA 线程从不为 COM 调用提供服务,而在工作线程上调用 Thread.Join() 时会被阻止。

我希望 STA 线程能够在 Thread.Join 上阻塞时为 COM 调用提供服务。

谁能解释一下这里可能发生了什么?


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 

以下是文章中显示的调用堆栈,适用于调用 Thread 的 STA 线程。加入: 它似乎与我在上次通话中看到的有所不同。

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

以下是本文的 MTA 线程的调用堆栈:

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

子栖 2024-08-09 17:43:37

您的工作线程是否在 MTA 公寓中运行?如果当前公寓是 MTA,则 Thread.Join 将不会执行泵送。在这种情况下,MSDN 上的文档具有误导性,因为标准做法是不注入 MTA。

这是一篇关于该主题的文章

编辑 重新阅读一下问题,发现阻塞线程是 STA 线程。作为 CW 留下答案,以防它可以帮助人们以所描述的方式解决问题

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文