加载中…
个人资料
南冠彤
南冠彤
  • 博客等级:
  • 博客积分:0
  • 博客访问:415,028
  • 关注人气:59
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
谁看过这篇博文
加载中…
正文 字体大小:

(转)线程的内存泄漏的主要原因

(2011-11-07 15:27:26)
标签:

杂谈

分类: CPP/C

在很多参考书上,都说不要用CreateThread 创建线程、并用CloseHandle来关闭这个线程,因为这样做会导致内存泄漏,而应该用_beginthread来创建线程,_endthread来销毁线程。其实,真正的原因并非如此。看如下一段代码:

HANDLE CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程安全属性

DWORD dwStackSize, // 堆栈大小

   LPTHREAD_START_ROUTINE lpStartAddress, // 线程函数

   LPVOID lpParameter, //线程参数

      DWORD dwCreationFlags, // 线程创建属性     

        LPDWORD lpThreadId // 线程ID

);

线程中止运行后,线程对象仍然在系统中,必须通过CloseHandle函数来关闭该线程对象。CloseHandle函数的原型是:

BOOL CloseHandle( HANDLE hObject // 对象句柄    );//HANDLE hObject // 对象句柄   

CloseHandle可以关闭多种类型的对象,比如文件对象等,这里使用这个函数来关闭线程对象。调用时,hObject为待关闭的线程对象的句柄。

说用这种方法时内存在泄漏,其实不完全正确。那为什么会引起内存的泄漏呢?因为当线程的函数用到了C的标准库的时候,很容易导致冲突,所以在创建VC的工程时,系统提示是用单线程还是用多线程的库,因为在C的内部有很多的全局变量。例如,出错号、文件句柄等全局变量。

因为在C的库中有全局变量,这样用C的库时,如果程序中使用了标准的C的库时,就很容易导致运行不正常,会引起很多的冲突。所以,微软和Borland都对C的库进行了一些改进。但是这个改进的一个条件就是如果一个线程已经开始创建了,就应该创建一个结构来包含这些全局变量,接着把这些全局变量放入线程的上下文中和这个线程相关起来。这样,全局变量就会依赖于这个线程,不会引起冲突。

这样做就会有一个问题,什么时候这个线程开始创建呢?标准的Windows的API是不知道的,因为它是静态的库。这些库都是放在VC的LIB的目录内的,而线程函数是操作系统的函数。所以,VC和BC在创建线程时,都会用_beginThread来创建线程,再用_endThread来结束线程。这样,它们在创建线程的时候,就会知道什么时候创建了线程,并把全局变量放入某一结构中,让它和线程能关联起来。这样就不会发生冲突了。

很显然,要完成这个功能,首先需要分配结构表把全局变量包含起来。这个过程是在_beginThread时做的,而释放在_endTread内完成。

所以,当用_beginThread来创建,而用CloseHandle来关闭线程时,这时复制的全局结构就不会被释放了,这就有了内存的泄漏。这就是很多资料所说的内存泄漏问题的真正的原因。

其实,可以不用_beginThread和_endThread这一对函数。如果用CreateThread函数创建,用CloseHandle关闭,那么,与C有关的库就会用全局的,它们会引起冲突。所以,比较好的方法就是在线程内不用标准的C的库(可以使用Windows API的库函数)。这样就不会有什么问题,也就不会引起冲突。例如,字符串的操作函数、文件操作等。

当某个程序创建一个线程后,会产生一个线程的句柄,线程的句柄 主要用来控制整个线程的运行,例如停止、挂起或设置线程的优先级等操作。一般来说,当线程启用后,就会用线程的CloseHandle来关闭线程。但在微 软的示例程序中,有一个例子创建以后,就马上调用CloseHandle关闭线程的运行。这样做在Windows 98下没什么问题,但在Windows NT下,内核就会出现错误。这是为什么呢?

这是因为虽然线程有关的结构已经释放了,但线程还在运行中,所以程序就会出现错误。那怎么做才能确保正常运行呢?

其实,要正常运行,可以让线程完全结束以后,再调用CloseHandle来释放资源。

怎样知道线程完全结束呢?在Windows 的API中有一类等待线程的命令:

DWORD WaitForSingleObject(

HANDLE hHandle, // handle to object to wait for

DWORD dwMilliseconds , // time-out interval in milliseconds

);

DWORD WaitForMultipleObjects(

DWORD nCount, // number of handles in the handle array

CONST HANDLE *lpHandles, // pointer to the object-handle array

BOOL fWaitAll, // wait flag

DWORD dwMilliseconds // time-out interval in milliseconds

);

可以用以上两函数,等待线程的结束。如果线程结束,函数就会返回。否则就一直等待,直到指定的时间结束。

还有一种线程根本不会退出,它一直运行着循环的线程。我们就要用中止线程的方法来结束线程的运行,强制把它关闭。强制关闭后,再用CloseHandle来释放结构

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有