欢迎来到天天文库
浏览记录
ID:11209905
大小:138.90 KB
页数:10页
时间:2018-07-10
《如何避免使用createthread函数导致的内存泄露》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库。
1、如何避免使用CreateThread函数导致的内存泄露 前阵子翻了翻候杰老师翻译的那本Win32多线程的书,老书了,很经典。 书里提到,当使用C/C++的时候,有些情况下CreateThread会导致内存泄露,建议使用_beginthread和_beginthreadex。这种泄露网上也有不少帖子在讲。 事实上,这种泄露的可能是存在的,但是只要稍微注意一下,是可以找到方法避免的。 CreateThread导致内存泄露的原因 这得从C运行时库说起了。 VC运行时库,有一个宏errno,用来获得上一步操作的错误码,类似于Win32中的GetLastErro
2、r()函数。在多线程环境下,不同线程调用errno返回的都是caller线程的错误码,绝对不会混淆,这是因为使用了TLS技术。 TLS,ThreadLocalStorage,是用来存取线程相关数据的一种技术,在Win32中由操作系统的Tls*系列函数提供支持。例如,可以在程序开始的地方调用TlsAlloc()函数,获得一个TLSindex,这个index在进程范围内有效,然后可以创建n个线程,在每个线程中使用TlsSetValue(index,data)将线程相关数据和index关联起来,使用TlsGetValue(index)来获取当前线程和index相关联的的线程相关
3、数据。 查看msdn可以发现,Tls*函数的定义如下:[cpp]viewplaincopyprint?1.DWORD WINAPI TlsAlloc(void); 2. 3.BOOL WINAPI TlsSetValue( 4. __in DWORD dwTlsIndex, 5. __in LPVOID lpTlsValue 6.); 7. 8.LPVOID WINAPI TlsGetValue( 9. __in DWORD dwTlsIndex 10.); 11. 12.BOOL WINA
4、PI TlsFree( 1. __in DWORD dwTlsIndex 2.); 观察TlsSetValue/TlsGetValue的原型可以发现,与index关联的数据只能是void*类型,因此通常的做法是在线程开始的时候,为这个线程分配一块内存,用于存储所有与线程相关的数据,然后把这块内存的起始地址与index关联起来。如果这块内存在线程退出的时候没有释放掉,那就有内存泄露的危险。 回到errno,来看看C运行时库是如何实现errno的。 errno的声明和实现如下:[c-sharp]viewplaincopyprint?1./
5、* error.h - errno的声明 */ 2._CRTIMP extern int * __cdecl _errno(void); 3.#define errno (*_errno()) 4. 5./* dosmap.c - errno的实现 */ 6.int * __cdecl _errno( 7. void 8. ) 9.{ 10. _ptiddata ptd = _getptd_noexit(); 11. if (!ptd) { 12. return &ErrnoNoMem; 13.
6、 } else { 14. return ( &ptd->_terrno ); 15. } 16.} 观察_errno的代码,函数首先调用了_getptd_noexit()函数,这个函数的代码如下:[cpp]viewplaincopyprint?1./* tiddata.c - _getptd_noexit()实现 */ 2._ptiddata __cdecl _getptd_noexit ( 3. void 4. ) 5.{ 6. _ptiddata ptd; 7. DWORD T
7、L_LastError; 8. 9. TL_LastError = GetLastError(); 10. 11.#ifdef _M_IX86 12. 13. /* 14. * Initialize FlsGetValue function pointer in TLS by calling __set_flsgetvalue() 15. */ 16. 17. if ( (ptd = (__set_flsgetvalue())(__flsindex))
此文档下载收益归作者所有