CreateThread与_beginthreadex 该用哪一个

来源:互联网 发布:同花顺画线工具源码 编辑:程序博客网 时间:2024/04/28 05:57
/* 3:_beginthreadex()源码
*/
// 线程本地存储:TLS(Thread Local Storage)
// 每个线程都有自己专用的一块内存区域, 不共享
__declspec(thread) int g_nData = 0; //这就是两个线程都要访问的变量


// 获取线程数据结构指针
_ptiddata __cdecl _getptd(void)
{
// 1:尝试获得当前的ptd
// 2:如果为空,就重新创建一个
}
// _getptd_noexit() 与 _getptd()功能类似
//  _getptd_noexit()函数首先通过TLS查找线程相关数据,如果没有找到,就分配一块内存,
// 存放_tiddata结构,并将这块内存与__flsindex相关联




_CRTIMP uintptr_t __cdecl _beginthreadex( void *security, unsigned stacksize,
unsigned (__stdcall * initialcode) (void *),
void * argument, unsigned createflag, unsigned *thrdaddr )
{
        _ptiddata ptd;                  /* 线程数据结构指针*/
        uintptr_t thdl;                 /* 线程句柄 */


        ptd = (_ptiddata)_calloc_crt(1, sizeof(struct _tiddata));// 给线程数据结构分配内存
        _initptd(ptd, _getptd()->ptlocinfo); // 初始化线程的_tiddata块即CRT数据区域
        ptd->_initaddr = (void *) initialcode; // 线程函数1
        ptd->_initarg = argument;
        ptd->_thandle = (uintptr_t)(-1);


// 调用CreateThread()创建线程, 线程函数2是_threadstartex()
        thdl = (uintptr_t)CreateThread( (LPSECURITY_ATTRIBUTES)security, stacksize,
_threadstartex, 
(LPVOID)ptd, createflag, (LPDWORD)thrdaddr);
        return(thdl);
}


static unsigned long WINAPI _threadstartex (void * ptd)
{
       _callthreadstartex()
  {
_ptiddata ptd = _getptd();

// 用户自定义线程函数地址
typedef unsigned (__CLR_OR_STD_CALL *PUSERTHREADPROC)(void *)
pUserThreadProc =  (unsigned (__CLR_OR_STD_CALL *)(void *))( ((_ptiddata)ptd)->_initaddr );
void* pInitArg = (_ptiddata)ptd)->_initarg;
_endthreadex( pUserThreadProc(pInitArg));// 执行用户自定义线程函数, 并结束线程
{
_ptiddata ptd = _getptd_noexit();
if (ptd) 
{
_freeptd(ptd);// 释放
}
ExitThread(retcode);
}
  }
}


/* 4:在CreateThread()创建的线程中使用 标准C运行库 中的函数 可能会导致内存泄露 的 原因
   例如使用_errno()函数会调用_getptd_noexit()获取_tiddata指针, 但是CreateThread()创建的线程中
没有_tiddata, _getptd_noexit()就会重新申请内存, 然而CreateThread()中并没有处理这块内存的释放
*/
int * __cdecl _errno(void)  
{  
    _ptiddata ptd = _getptd_noexit();  
    if (!ptd) {  
        return &ErrnoNoMem;  
    } else {  
        return ( &ptd->_terrno );  
    }  



/* 5:避免CreateThread引发泄露,大致有几种方法:
      1. 使用_beginthread/_beginthreadex函数创建线程
      2. 在线程函数return前,显示调用_endthread/_endthreadex函数
      3. 在线程函数return前,显示调用_freeptd(NULL),此方法在C语言中有效
      4. 使用/MTd或/MDd参数
*/ 


/* 6:一定不要使用TerminateThread函数来终止线程
   在连接静态库的情况下,TerminateThread会使线程直接被终止,因此没有释放ptd的机会;
在连接静态库的情况下,DLL_THREAD_DETACH只有在线程正常退出时才会产生, 因此被终止的线
程的ptd同样不会被释放.
*/
0 0
原创粉丝点击