天天看点

winform 线程 句柄不断增加_Deleaker专题:未调用CloseHandle导致的线程句柄泄漏问题...问题分析解决办法:CloseHandle结论

多线程应用中常常使用_beginthreadex函数来创建线程,在线程同步中,往往需要等待一个线程执行结束,这时WaitForSingleObject就可以派上用场。今天主要是研究线程句柄资源泄漏的问题。

问题分析

在本文中,我们主要使用到了资源泄漏检测利器Deleaker。先考察以下示例程序:

winform 线程 句柄不断增加_Deleaker专题:未调用CloseHandle导致的线程句柄泄漏问题...问题分析解决办法:CloseHandle结论

主程序调用_beginthreadex创建了一个线程,线程过程为TestThreadProc。线程什么也不干,就是等待3秒钟然后退出。主线程创建线程后立即等待线程执行结束,线程执行结束后,WaitForSingleObject返回WAIT_OBJECT_0,然后整个程序退出。一切都那么简单而美好。

我们使用Deleaker对程序的资源泄漏情况做检测,检测结果如下:

winform 线程 句柄不断增加_Deleaker专题:未调用CloseHandle导致的线程句柄泄漏问题...问题分析解决办法:CloseHandle结论

可以看到,我们的程序存在线程句柄泄漏。为什么呢?

执行_beginthreadex后,线程内核对象创建,引用计数增加为1,WaitForSingleObject等待线程结束后,主程序也随之退出了,但是,线程内核对象的引用计数仍然为1,所以,一直到主程序退出之前,此线程内核对象都得不到释放,即使线程过程早已执行完毕了。

这个问题,在简单系统中可能不会造成大的影响,但在大型多线程系统中,很多工作线程往往会频繁创建和退出,如果未能及时释放线程内核对象,则导致程序随着时间的累积,资源占用越来越多,导致最终资源耗尽。

解决办法:CloseHandle

我们可以通过调用CloseHandle来将线程内核对象自减1,当线程内核对象的引用计数减至0时,系统自动释放线程内核对象,从而释放和该线程绑定在一起的所有资源。以下是修正后的程序:

winform 线程 句柄不断增加_Deleaker专题:未调用CloseHandle导致的线程句柄泄漏问题...问题分析解决办法:CloseHandle结论

再次使用Deleaker做检测,可以看到没有再出现线程句柄泄漏的问题。

winform 线程 句柄不断增加_Deleaker专题:未调用CloseHandle导致的线程句柄泄漏问题...问题分析解决办法:CloseHandle结论

结论

程序设计人员就如同艺术家一样,需要对自己的程序精心雕琢,力求完美。在这条路上,资源泄漏是我们必然会碰到的问题,面对这个问题,你会采取什么态度?我们往往说的匠心,也许就是指:碰到资源泄漏时,停下开发的脚步,查明泄漏的原因并修复。