描述:
Windows XP,Visual Studio 2008, C++ 环境下,调试控制台应用程序,中途强制退出。结果任务栏和任务管理弹出一个控制台窗口,点击关闭或结束任务无效。进程管理器里没有发现此窗口相关进程。如果选择关机,则无限等待ing,只能被迫关电源。
分析:
很诡异的现象,以前没遇过,难道这个窗口是个幽灵窗口?嗯……科学不能迷信,虽然已是深夜,但还是着手研究一下。不能正常关机确实问题很大。而且我经常要用调试器,这下要我怎么活啊?
从现象分析一下,窗口点击无反应的原因一般就几个:
1. CPU忙,进程优先级低
2. 进程忙
3. 进程锁死,或者不存在
初步排除了一下,CPU是很空闲的,而所有进程也是空闲。怀疑进程异常了,用IceSword监控进程创建和结束过程,一切正常。test.exe(vs编译出来的程序名称)被devenv.exe(vs的ide)创建和结束。进程ID也配对。在进程管理器里重新查找ID,确认已经结束了。
那为什么进程对应的窗口没有消失呢?难道是windows或vs2008的bug?之前一直用vs2008,没有发现这样的问题啊?最近这个问题却频繁出现了。
那可能是代码中某些部分影响了这样的结果。再仔细分析一下最近的代码有什么共同点。突然发现,因为最近经常需要调试大量数据的关系,常常把标准输入输出替换成文件输入输出。经过反复测试,发现文件输出中途,如果用调试器强制退出,就这发生问题。如果文件未开始输出,或已输出完毕,就没有问题。
代码大概如:
file.open("output.txt");
file<<"Hello";
while ( true ) { ... } // bug, always loop...
file.close();
因为我调试的程序,是可能出现死循环的程序。调试发现程序错误时,只能选择中途强退(debug的stop功能)。我还有其它办法吗?
经过尝试,发现如果把断点清空,让程序一直跑,然后在控制台窗口直接点击关闭。就没有上述问题了。哈哈,这个办法可行!起码不假死机了。
这个因为进程的结束是由它自己控制的,不是vs2008强制结束的。所以一切都合情合理。
结论:
总的来说,这个应该是vs2008的bug,vs6没有这个问题。
窗口和进程是不同的概念,窗口存在不等同于进程存在。虽然大部分应用程序看上去,这两者没区别。但是windows底层对它们的处理可是完全的不同。窗口是由进程创建,也是由进程关闭。我们平时点击窗口的x键,都是发送关闭消息给进程,由进程处理消息(例如检查需不需要保存),处理完毕后在进行关闭窗口过程。
如果进程被异常结束了,而窗口还没有关闭的话,就是进入假死状态。此窗口的关闭消息没有相应的进程处理,窗口就会一直残留在windows里。连关机程序都动不了这个窗口。而此时我们的思路还停留在查找进程上面,完全被这个幽灵窗口搞的一头雾水。