Jeffrey Richter 给出的一些注解:
first, if you call _beginthreadex, you'll get back a handle to the thread. At some point, that thread's handle must be closed. _endthreadex **doesn't** do it. Normally, the thread that called _beginthreadex (possibly the main thread) will call CloseHandle on the newly created thread's handle when the thread handle is no longer needed. Second, you only need to use _beginthreadex if your app uses CRT functions. If it doesn't, then you can just use CreateThread. Also, you can use CreateThread if only one thread (the main thread) in your app uses the CRT. If newly created threads don't use the CRT, you don't need _beginthreadex or the multithreaded CRT.
_ptiddata ptd; // Pointer to thread's data block
unsigned long thdl; // Thread's handle
// Allocate data block for the new thread
if ((ptd = calloccrt(1, sizeof(struct tiddata))) == NULL)
goto errorreturn;
// Initialize the data block
initptd(ptd);
// Save the desired thread function and the parameter
// we want it to get in the data block
ptd->_initaddr = (void *) pfnStartAddr;
ptd->_initarg = pvParam;
// Create the new thread
thdl = (unsigned long) CreateThread(psa, cbStack,
_threadstartex, (PVOID) ptd, fdwCreate, pdwThreadID);
if (thdl == NULL) {
// Thread couldn't be created, cleanup and return failure
goto error_return;
}
// Create created OK, return the handle
return(thdl);
error_return:
// Error: data block or thread couldn't be created
_free_crt(ptd);
return((unsigned long)0L);
}
void __cdecl _endthreadex (unsigned retcode) {
_ptiddata ptd; // Pointer to thread's data block
// Cleanup floating-point support (code not shown)
// Get the address of this thread's tiddata block
ptd = _getptd();
/*
* Allocate and initialize a per-thread data structure for the to-
* be-created thread.
*/
if ( (ptd = _calloc_crt(1, sizeof(struct _tiddata))) == NULL )
goto error_return;
/*
* 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( security,
stacksize,
_threadstartex,
(LPVOID)ptd,
createflag,
thrdaddr))
== (uintptr_t)0 )
{
errcode = 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 ( errcode != 0L )
_dosmaperr(errcode);
return( (uintptr_t)0 );
}
/***
*_threadstartex() - New thread begins here
*
*Purpose:
* The new thread begins execution here. This routine, in turn,
* passes control to the user's code.
*
*Entry:
* void *ptd = pointer to _tiddata structure for this thread
*
*Exit:
* Never returns - terminates thread!
*
*Exceptions:
*
*******************************************************************************/
static unsigned long WINAPI _threadstartex (
void * ptd
)
{
_ptiddata _ptd; /* pointer to per-thread data */
/*
* Check if ptd is initialised during THREAD_ATTACH call to dll mains
*/
if ( ( _ptd = FLS_GETVALUE(__tlsindex)) == NULL)
{
/*
* Stash the pointer to the per-thread data stucture in TLS
*/
if ( !FLS_SETVALUE(__tlsindex, ptd) )
_amsg_exit(_RT_THREAD);
/*
* Set the thread ID field -- parent thread cannot set it after
* CreateThread() returns since the child thread might have run
* to completion and already freed its per-thread data block!
*/
((_ptiddata) ptd)->_tid = GetCurrentThreadId();
}
else
{
_ptd->_initaddr = ((_ptiddata) ptd)->_initaddr;
_ptd->_initarg = ((_ptiddata) ptd)->_initarg;
_free_crt(ptd);
ptd = _ptd;
}
/*
* Call fp initialization, if necessary
*/
if ( _FPmtinit != NULL )
(*_FPmtinit)();
/*
* Guard call to user code with a _try - _except statement to
* implement runtime errors and signal support
*/
__try {
_endthreadex (
( (unsigned (WINAPI *)(void *))(((_ptiddata)ptd)->_initaddr) )
( ((_ptiddata)ptd)->_initarg ) ) ;
}
__except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
{
/*
* Should never reach here
*/
_exit( GetExceptionCode() );
/*
* Call fp termination, if necessary
*/
if ( _FPmtterm != NULL )
(*_FPmtterm)();
if ( (ptd = _getptd()) == NULL )
_amsg_exit(_RT_THREAD);
/*
* Free up the _tiddata structure & its subordinate buffers
* _freeptd() will also clear the value for this thread
* of the FLS variable __tlsindex.
*/
_freeptd(ptd);
谢谢楼上各位的回答.
weirdy说, beginthreadex会自动调用_endthreadex ,我看了代码, 它只是__createthreadex错误返回时才释放,我的问题是从线程函数正常return情况下.不显式调用__endthreadex,这个_tiddata是否会释放,如果不释放,又该怎么办?
如下:
* 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 ( errcode != 0L )
_dosmaperr(errcode);