CreateThread与_beginthreadex的区别和应用场景
我查了好多网上的资料,知道这两者的区别是一个是winapi,一个是c run-time 库。我想问的问题是:
1、winapi与c run-time库有何区别?
2、这两者的应用场景有何不同?我发现在我们的产品代码中只用到了CreateThread,根本没有使用_beginthreadex这个函数。
[解决办法]
1,运行时库最终也是调用API
2,运行时库做的事情更多
[解决办法]
如果你产品中全用WinAPI,那么CreateThread自然没问题
某些库函数在CreateThread下会有问题,请参见《Windows核心编程》,所以使用了线程不安全的库函数和修改errno的库函数,请使用_beginthreadex
[解决办法]
1 _beginthreadex初始化线程的运行库环境,比如线程的errno。
2 C/C++程序最简单的规则就是 禁止使用CreateThread。
否则C运行库的不少函数都是不能使用的,太容易误用了。
[解决办法]
只要连接到多线程环境的CRT,即使是CreateThread也能保证库函数正确调用,但是在线程关闭的时候,这会导致由库函数引起的内存泄露。因此微软引入了_beginthread/_endthread和_beginthreadex/_endthreadex来解决内存泄露的问题。
[解决办法]
CreateThread本身没有什么问题,在遇到下面等等函数的时候会现场创建tiddata,
_doserrno, strtok, _wcstok, strerror, _strerror, tmpnam, tmpfile.....
你自己调用_endthreadex释放tiddata就好了。
如果你不确保你记得调用_endthreadex或者觉得别扭,那就换成_beginthreadex。
另外,如果你不想发生像下面这个帖子中可能让你困惑的报错的话,就用_benginthreadex吧
http://topic.csdn.net/u/20120905/14/0bc482cc-0f91-4e18-b6b2-28811ff9b26c.html
[解决办法]
《Windows核心编程》
[解决办法]
最好的方法是看_beginthreadex()的实现,看看它的比CreateThread多做了些什么操作
/****_beginthreadex() - Create a child thread**Purpose:* Create a child thread.**Entry:* *** Same parameters as the Win32 API CreateThread() **** security = security descriptor for the new thread* stacksize = size of stack* initialcode = pointer to thread's startup code address* must be a __stdcall function returning an unsigned.* argument = argument to be passed to new thread* createflag = flag to create thread in a suspended state* thrdaddr = points to an int to receive the ID of the new thread**Exit:* *** Same as the Win32 API CreateThread() ***** success = handle for new thread if successful** failure = 0 in case of error, errno and _doserrno are set**Exceptions:**Notes:* This routine is more like the Win32 API CreateThread() than it* is like the C run-time routine _beginthread(). Ditto for* _endthreadex() and the Win32 API ExitThread() versus _endthread().** Differences between _beginthread/_endthread and the "ex" versions:** 1) _beginthreadex takes the 3 extra parameters to CreateThread* which are lacking in _beginthread():* A) security descriptor for the new thread* B) initial thread state (running/asleep)* C) pointer to return ID of newly created thread** 2) The routine passed to _beginthread() must be __cdecl and has* no return code, but the routine passed to _beginthreadex()* must be __stdcall and returns a thread exit code. _endthread* likewise takes no parameter and calls ExitThread() with a* parameter of zero, but _endthreadex() takes a parameter as* thread exit code.** 3) _endthread implicitly closes the handle to the thread, but* _endthreadex does not!** 4) _beginthread returns -1 for failure, _beginthreadex returns* 0 for failure (just like CreateThread).********************************************************************************/_MCRTIMP uintptr_t __cdecl _beginthreadex ( void *security, unsigned stacksize, unsigned (__CLR_OR_STD_CALL * initialcode) (void *), void * argument, unsigned createflag, unsigned *thrdaddr ){ _ptiddata ptd; /* pointer to per-thread data */ uintptr_t thdl; /* thread handle */ unsigned long err = 0L; /* Return from GetLastError() */ unsigned dummyid; /* dummy returned thread ID */ /* validation section */ _VALIDATE_RETURN(initialcode != NULL, EINVAL, 0); /* Initialize FlsGetValue function pointer */ __set_flsgetvalue(); /* * Allocate and initialize a per-thread data structure for the to- * be-created thread. */ if ( (ptd = (_ptiddata)_calloc_crt(1, sizeof(struct _tiddata))) == NULL ) goto error_return; /* * Initialize the per-thread data */ _initptd(ptd, _getptd()->ptlocinfo); ptd->_initaddr = (void *) initialcode; ptd->_initarg = argument; ptd->_thandle = (uintptr_t)(-1);#if defined (_M_CEE) || defined (MRTDLL) if(!_getdomain(&(ptd->__initDomain))) { goto error_return; }#endif /* defined (_M_CEE) || defined (MRTDLL) */ /* * Make sure non-NULL thrdaddr is passed to CreateThread */ if ( thrdaddr == NULL ) thrdaddr = &dummyid; /* * Create the new thread using the parameters supplied by the caller. */ if ( (thdl = (uintptr_t) CreateThread( (LPSECURITY_ATTRIBUTES)security, stacksize, _threadstartex, (LPVOID)ptd, createflag, (LPDWORD)thrdaddr)) == (uintptr_t)0 ) { err = GetLastError(); goto error_return; } /* * Good return */ return(thdl); /* * Error return */error_return: /* * Either ptd is NULL, or it points to the no-longer-necessary block * calloc-ed for the _tiddata struct which should now be freed up. */ _free_crt(ptd); /* * Map the error, if necessary. * * Note: this routine returns 0 for failure, just like the Win32 * API CreateThread, but _beginthread() returns -1 for failure. */ if ( err != 0L ) _dosmaperr(err); return( (uintptr_t)0 );}