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同样不会被释放.
*/
*/
// 线程本地存储: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
- CreateThread与_beginthreadex 该用哪一个
- CreateThread与_beginthreadex
- 用_beginthreadex不用 CreateThread
- CreateThread与_beginthreadex本质区别
- CreateThread与_beginthreadex本质区别
- _beginthreadex 与 createthread 的区别
- CreateThread与_beginthreadex本质区别
- _beginThreadex 与 CreateThread 的区别
- CreateThread与_beginthreadex和_beginthread
- CreateThread与_beginthreadex本质区别
- CreateThread与_beginthreadex的区别
- CreateThread与_beginthreadex本质区别
- _beginthreadex&&CreateThread
- _beginthreadex与CreateThread区别与联系
- _beginthreadex与CreateThread区别与联系
- _beginthreadex与CreateThread区别与联系
- CreateThread()、_beginthread()以及_beginthreadex()联系与区别
- CreateThread()、_beginthread()以及_beginthreadex()联系与区别
- windows 7旗舰版升级windows 10专业版,全过程
- hdu 1181 变形记
- ActionMQ5.8.0 JMS实例
- C# Asp.net 前台使用utf-8编码传递中文参数 后台接收乱码的问题
- 《算法导论》— Chapter 15 动态规划
- CreateThread与_beginthreadex 该用哪一个
- 无法打开 /var/log/sysstat/sa05: 没有那个文件或目录
- 深入理解ThreadPoolExecutor运转机制
- 利用img标签,可以为网站设置多张默认图片
- POJ 2192 Zipper
- Android系统安全和反编译实战——互动出版网
- 最新app store 应用提交经验分享
- Qt Creator设置黑色主题背景
- 浅谈HTTP中Get与Post的区别