我有一个原生的Visual C ++ NT服务。当服务启动时,它的线程调用CoInitialize()
将线程附加到STA - 服务线程通过COM接口使用MSXML。
当服务收到SERVICE_CONTROL_STOP
时,它会在消息队列中发布消息,然后检索该消息并调用OnStop()
处理程序。处理程序清理内容并调用CoUnitialize()
。大部分时间它都可以正常工作,但偶尔会在后面调用挂起。我无法稳定地重现这种行为。
我用Google搜索了一段时间后发现了以下可能的解释:
CoInitializeEx()
/CoUnitialize()
for attaching to MTA 第一个不太可能 - 使用MSXML的代码经过了充分测试和分析,它使用智能指针来控制对象的生命周期,因此泄漏对象的可能性很小。
第二个看起来不是可能的原因。我附加到STA,不要重复调用这些函数。
第三个看起来或多或少。当线程正在处理消息时,它不再运行消息循环 - 它已经在循环内部。我想这可能是原因。
后者可能是造成这个问题的原因吗?我应该考虑其他什么原因?如何轻松解决此问题?
答案 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处理程序等待主线程处理请求。这是一个普通的僵局。