Deleaker专题:未调用CloseHandle导致的线程句柄泄漏问题
多线程应用中常常使用_beginthreadex函数来创建线程,在线程同步中,往往需要等待一个线程执行结束,这时WaitForSingleObject就可以派上用场。今天主要是研究线程句柄资源泄漏的问题。
在本文中,我们主要使用到了资源泄漏检测利器Deleaker。先考察以下示例程序:
unsigned _stdcall TestThreadProc(void * param) { Sleep(3000); return 0; } int _tmain(int argc, _TCHAR* argv[]) { HANDLE hThread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, TestThreadProc, NULL, 0, NULL)); WaitForSingleObject(hThread, INFINITE); return 0; }
主程序调用_beginthreadex创建了一个线程,线程过程为TestThreadProc。线程什么也不干,就是等待3秒钟然后退出。主线程创建线程后立即等待线程执行结束,线程执行结束后,WaitForSingleObject返回WAIT_OBJECT_0,然后整个程序退出。一切都那么简单而美好。
我们使用Deleaker对程序的资源泄漏情况做检测,检测结果如下:
可以看到,我们的程序存在线程句柄泄漏。为什么呢?
执行_beginthreadex后,线程内核对象创建,引用计数增加为1,WaitForSingleObject等待线程结束后,主程序也随之退出了,但是,线程内核对象的引用计数仍然为1,所以,一直到主程序退出之前,此线程内核对象都得不到释放,即使线程过程早已执行完毕了。
这个问题,在简单系统中可能不会造成大的影响,但在大型多线程系统中,很多工作线程往往会频繁创建和退出,如果未能及时释放线程内核对象,则导致程序随着时间的累积,资源占用越来越多,导致最终资源耗尽。
解决办法:CloseHandle
我们可以通过调用CloseHandle来将线程内核对象自减1,当线程内核对象的引用计数减至0时,系统自动释放线程内核对象,从而释放和该线程绑定在一起的所有资源。以下是修正后的程序:
unsigned _stdcall TestThreadProc(void * param) { Sleep(3000); return 0; } int _tmain(int argc, _TCHAR* argv[]) { HANDLE hThread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, TestThreadProc, NULL, 0, NULL)); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); return 0; }
再次使用Deleaker做检测,可以看到没有再出现线程句柄泄漏的问题。
结论:
程序设计人员就如同艺术家一样,需要对自己的程序精心雕琢,力求完美。在这条路上,资源泄漏是我们必然会碰到的问题,面对这个问题,你会采取什么态度?我们往往说的匠心,也许就是指:碰到资源泄漏时,停下开发的脚步,查明泄漏的原因并修复。
相关推荐
- 滚动条第6章节:鼠标滚轮的处理
- Posted on 12月18日
- 信号量对象没有所有者
- Posted on 05月29日
- 关于ListView控件的兼容性的一则轶事
- Posted on 12月02日
- 请勿使用PostMessage来模拟键盘输入
- Posted on 11月07日
评论已关闭。