我遇到了一个最近出现的问题,在某些情况下,Visual Studio 2005调试器中运行的应用程序将无法完全退出。 Visual Studio似乎已经终止了进程,调试器确实从进程中分离出来,我可以编译源代码更改。
然而,在链接编译器输出期间,我将看到一个错误,指示无法打开目标文件(通常是几个DLL中的一个,具体取决于正在重新编译的内容)。
如果我然后调出任务管理器,我可以在进程列表中看到该应用程序。但是,当我尝试终止进程时没有任何变化。我可以尝试进行调试 - >在Visual Studio中附加进程,该进程在列表中,但是Attach不起作用。
我怀疑这是一种一直存在的竞争条件,而不是由于最近的一些变化。多年来,我们已经看到了一些罕见的问题,其中应用程序似乎终止但在任务管理器中仍然可见,要求重新启动终端或使用任务管理器终止进程。但是,这种新行为有点不同,因为任务管理器无法终止该过程。
在任务管理器中,我尝试使用此屏幕截图显示的结果附加调试器。该应用程序似乎已附加调试器。
我最终要做的是重新启动Windows以便能够继续我的工作。
这不会一直发生。
一两天前我终于幸运了,我想我有更多关于这个问题的信息。看起来我在至少两个尝试使用Windows Critical Section对象执行某些操作的线程之间存在竞争条件。一个线程正在使用临界区与其他线程同步,用于公共设备,即串行通信端口。另一个线程正在处理DLL Detach,DLL Detach的代码在应用程序终止时删除了Critical Section对象。
查看DeleteCriticalSection function in MSDN online,有以下注释。
删除关键部分对象会释放所有使用的系统资源 由对象。呼叫者负责确保 临界区对象是无主的,并且是指定的CRITICAL_SECTION 任何关键部分功能都不会访问结构 在此过程中由其他线程调用。
删除关键部分对象后,请勿引用 任何在关键部分上运行的函数中的对象(例如
EnterCriticalSection
,TryEnterCriticalSection
和。{LeaveCriticalSection
以外的InitializeCriticalSection
和。{InitializeCriticalSectionAndSpinCount
。如果你试图这样做,记忆 可能会发生腐败和其他意外错误。如果关键部分在仍然拥有时被删除,则状态为 等待已删除的关键部分的所有权的线程是 未定义。
该部分应用程序的体系结构如下。有一个平台独立库实现为DLL,它导出一组其他人使用的函数。由于许多这些函数在DLL源代码中使用由多个线程共享的数据结构(主要是句柄表),因此它使用Windows Critical Sections来强制执行独占访问。首次在应用程序启动时附加DLL时,初始化包括创建所需的关键部分对象。在应用程序终止时分离DLL时,将删除关键部分对象。
当触发DLL分离时,线程完全有可能处于临界区等待队列中。所以问题的一部分可能是当仍有线程使用DLL时会触发DLL Detach。
我的问题假设这个僵尸进程的根本问题是一个等待被破坏的关键部分的线程,我该怎么做才能消除这种可能性?
作为一个侧面问题,一个问题是这个架构是否正确使用带有多线程应用程序的DLL。可能是,而不是试图删除关键部分对象,而是应该使用DLL Detach来清理Windows。
阅读DllMain entry point in the MSDN online有这样的说明:
当处理DLL_PROCESS_DETACH时,DLL应该释放诸如的资源 只有在动态卸载DLL时才会堆内存( lpReserved参数为NULL)。如果过程终止( lpvReserved参数是非NULL),进程中的所有线程除外 当前线程已经退出或已经明确退出 通过调用ExitProcess函数终止,该函数可能会离开 一些进程资源,例如处于不一致状态的堆。在这 例如,DLL清理资源是不安全的。代替, DLL应该允许操作系统回收内存。
附加说明
注1: Cleaning up shared resources when a process is abnormally terminated在调试器中运行时有关于DLL和进程终止的说法,这意味着这可能只是开发人员测试环境问题(尽管仍然很痛苦) :
将代码放入DllMain不起作用,因为,作为Darren 观察到,当进程终止时,不会调用DllMain 突然(比如退出调试器时)。
对我而言,正确的解决方案是使用互斥锁来保护共享 内存区域,如果任何等待互斥锁的人被唤醒 用WAIT_ABANDONED,他们需要认识到的所有者 mutex终止而不释放资源并清理。