如何解决CoUnitialize()上挂起的进程?

时间:2010-09-29 11:03:40

标签: windows visual-c++ winapi com windows-services

我有一个原生的Visual C ++ NT服务。当服务启动时,它的线程调用CoInitialize()将线程附加到STA - 服务线程通过COM接口使用MSXML。

当服务收到SERVICE_CONTROL_STOP时,它会在消息队列中发布消息,然后检索该消息并调用OnStop()处理程序。处理程序清理内容并调用CoUnitialize()。大部分时间它都可以正常工作,但偶尔会在后面调用挂起。我无法稳定地重现这种行为。

我用Google搜索了一段时间后发现了以下可能的解释:

  1. 未能释放所有拥有的COM对象
  2. repeatedly calling CoInitializeEx()/CoUnitialize() for attaching to MTA
  3. failing to dispatch messaged in STA threads
  4. 第一个不太可能 - 使用MSXML的代码经过了充分测试和分析,它使用智能指针来控制对象的生命周期,因此泄漏对象的可能性很小。

    第二个看起来不是可能的原因。我附加到STA,不要重复调用这些函数。

    第三个看起来或多或少。当线程正在处理消息时,它不再运行消息循环 - 它已经在循环内部。我想这可能是原因。

    后者可能是造成这个问题的原因吗?我应该考虑其他什么原因?如何轻松解决此问题?

2 个答案:

答案 0 :(得分:3)

在处理SCM消息的线程中不要做任何后果,它处于一个奇怪的魔法环境中 - 你必须尽可能快地回答SCM的请求而不采取任何阻止操作。告诉它你需要额外的时间通过STOP_PENDING,排队另一个线程进行真正的清理,然后立即完成SCM消息。

关于CoUninitialize,只需附加WinDbg并转储所有线程 - 死锁很容易诊断(也许不能解决!),你已经在堆栈中找到了犯罪的所有各方。

答案 1 :(得分:1)

经过非常仔细的分析并使用Visual Studio调试器(感谢user Pall Betts pointing out获取证据很重要)来检查所有活动线程,我发现该进程不会挂起来调用{{1而是在CoUninitialize()之前从我们的程序代码调用的RpcServerUnregisterIf()函数。这是一个序列图:

CoUninitialize()

发出入站RPC请求,RPC运行时生成一个线程来为其提供服务。请求处理程序将请求排队到工作线程并等待。

现在月相碰巧恰到好处,因此WorkerThread RpcThread OuterWorld |----| Post "stop service" message | | |<---| | SomeRpcServerMethod() | | Post "process rpc request" |<---------------------------| |<----------------------------------------| waits | |----|Wait until |----| Process "stop service" message | |request is processed |<---| (call OnStop()) | |by the worker thread | | | |----| RpcServerUnregisterIf() | | |X<--| Wait all rpc requests complete |X<--| | | 与RPC线程中的处理程序并行执行。 RpcServerUnregisterIf()等待所有入站RPC请求完成,RPC处理程序等待主线程处理请求。这是一个普通的僵局。