您的位置:首页 > 其它

程序退出时意外终止和程序不能关掉(必须通过任务管理器关闭)的原因(续)

2011-12-26 14:52 351 查看
一、问题描述

描述:在上一篇中提到了CBioUSBAPI类存在bug使得程序退出后进行仍然驻留在内存中(后经验证,若注释掉CBioUSBAPI类的析构函数,则程序正常),必须通过任务管理器去强制关闭。

最近在制作两级对话框的时候又出现了与CBioUSBAPI类有关的错误问题:制作返回上一级对话框时界面卡死。后经验证,若注释掉CBioUSBAPI类的析构函数,则程序正常。

看来虽然两者错误的表象不一样,但问题的根源都出在了CBioUSBAPI类的构造函数上。

二、大胆猜测

猜测:从错误的表象来看,虽然一个是程序仍然驻留内存,一个界面关闭时卡死,但根源应该还是在于对话框退出时候其进程没有销毁。

三、发现问题

解决:最终发现问题出现在CBioUSBAPI类析构函数中调用了如下语句:

// wait until the read/write and in/out thread destroyed
while((hEvent_Read != NULL) || (hEvent_IoControl!=NULL));


在此处设置断点发现while的判断语句始终为TRUE,导致程序停在了这里。这与前面的猜测基本吻合:即由于程序代码执行到这里就停止了,导致其进程无法关闭。

四、解决问题

这个while循环的意思应该是等待变量不为空,不管那么多了,先注释掉此句,发现先前存在的问题解决了。但在后面的关闭进程中又出现了异常:

First-chance exception at 0x7c92e4ff in RowDemo.exe: 0xC0000008: An invalid handle was specified.

Unhandled exception at 0x7c92e4ff in RowDemo.exe: 0xC0000008: An invalid handle was specified.

The thread 'Win32 Thread' (0x1308) has exited with code 0 (0x0).

通过设置断点找到出现异常抛出的位置在CloseHandle(hThread_IoControl);上

if(hThread_IoControl != NULL)
{
CloseHandle(hThread_IoControl);             //异常抛出的位置
hThread_IoControl = NULL;
}

再通过watch窗口跟踪发现 hThread_IoControl变量值为0xcdcdcdcd,说明此变量是没有初始化的变量。因此要closeHandle去关闭一个没有初始化的句柄当然会报错。这里要注意的是变量没有初始化与变量为NULL(值为0x00000000)在vc中是两个不同的概念。

下面的试验也验证了这一点,如下调用是不会出现异常抛出错误的:

hThread_IoControl=NULL;	//注意是NULL(0x00000000),而非0xcdcdcdcd

closeHandle(hThread_IoControl)

但是若hThread_IoControl=0xcdcdcdcd,则不行。

为什么会这样呢?主要是因为在vc中,在debug模式下,0xcdcdcdcd是当变量没有初始化时编译器默认的变量初始化值(0xcdcdcdcd是编译器默认的自动变量初始化值;编译器把所有未使用的内存都初始化成0xCD)。而NULL的值为0x00000000,这两个概念是不同的。因此当我们声明一个指针变量后,都要将NULL赋值给它,否则将会是野指针。

int * p; //没有初始化的野指针 。debug下在VC中值为0xcdcdcdcd

p = NULL; //这样才安全。值为0x00000000

//所以一般这么申明

int* p = NULL;

五、最后的代码

最后经证实,hThread_IoControl变量是我们的工程师先前创建一个读I/O线程时候开辟的,但他给我源代码的时候创建部分已经被它屏蔽了,但他却忘记把删除部分屏蔽了,结果就···

hThread_IoControl = (HANDLE)CreateThread(NULL,
0,
ThreadExecute_IoControl,
this,
0,
&dwThreadID_IoControl);

最后的正确代码应该是先在头文件中删除hThread_IoControl变量的声明,同时在析构函数中删除有关hThread_IoControl变量的代码,即while循环改成:

while((hEvent_Read != NULL));


注释掉关闭hThread_IoControl线程句柄部分的代码:

//if(hThread_IoControl != NULL)
//	{
//		CloseHandle(hThread_IoControl);
//		hThread_IoControl = NULL;
//	}


六、总结

唉,看来养成一个良好的编程习惯比啥都重要哈
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐