Windows thread Health (illustrated)

Source: Internet
Author: User
Tags goto message queue

One, thread creation

When created, a Windows thread creates a thread kernel object, which is a small data structure that the operating system uses to manage threads. The new thread can access all handles to the process kernel object, all memory in the process, and stacks of other threads in the same process.

There are several ways to create a separate description of the

    1. CreateThread (...) (The API provided by the operating system, try not to use it)
    2. _beginthread (...)
    3. _beginthreadex (...)
    4. AfxBeginThread (...) (Interface provided by MFC)

First, a thread function is declared, and the prototype is:

DWORD Funthread (LPVOID pparam);
1. CreateThread ()

This function is provided for the operating system and is prototyped as follows:

HANDLE WINAPI CreateThread (  _in_opt_   lpsecurity_attributes lpthreadattributes,  _in_       size_t Dwstacksize,  _in_       lpthread_start_routine lpstartaddress,  _in_opt_   lpvoid lpparameter,  _In_       DWORD dwcreationflags,  _out_opt_  lpdword lpthreadid);

Description

Header Library Dll
WinBase.h Kernel32.lib Kernel32.dll

Parameters:

Lpthreadattributes: A pointer to the security_attributes struct that records the thread's security description. Determines whether the child process can inherit to the returned handle, if NULL, with the default security level (Thread_priority_normal), and the return handle cannot inherit
Dwstacksize: Specifies the thread stack size, when 0 o'clock, indicates that the stack uses the default size
Lpstartaddress: Thread function pointer
Lpparameter: Thread function parameters
dwCreationFlags: 0: Indicates that the thread is running immediately after it is created, Create_suspend: Pending after creation, the thread properties can be modified at this time, wake-up by ResumeThread;
Lpthreadid: A pointer to ThreadID, if the thread ID is concerned, the value is passed, otherwise null

return value:

Creates a handle to the thread;

If the creation fails, it returns NULL, and GetLastError () can be used to catch the error;

MFC also provides the CreateThread function, which is a method of the CWinThread class, as follows

BOOL CreateThread (   DWORD dwcreateflags = 0,   UINT nstacksize = 0,   lpsecurity_attributes lpsecurityattrs = NULL);

The meaning of the parameter is the same as the return value, and it is invoked in the following way:

CWinThread Thread1;thread1. CreateThread ();

It is necessary to note that when the Dwcreateflags value is Create_suspend, it is awakened by CWinThread::ResumeThread.

2. _beginthread (), _beginthreadex ()

Prototype:

unsigned long _beginthread (         void (__cdecl *start_address) (void *),         unsigned stack_size, void *arglist); Unsigne D Long _beginthreadex (         void *security,         unsigned stack_size,         unsigned (__stdcall *start_address) (void *), C5/>void *arglist,         unsigned initflag,         unsigned *thrdaddr);            

Description

Header Library
Process.h LIBCMT.lib MSVCRT.lib

The parameter is the same as above createthread meaning, not repeating;

Comparison:

1. _beginthread thread function call is _cdecl, and no return value; _beginthreadex is _stdcall and has a return value;

2. _beginthreadex in Initflag equivalent to CreateThread in dwcreationflags,thrdaddr equivalent to Lpthreadid

3. On the implementation of _beginthreadex control a _tiddata thread data block, which contains the thread function address, parameters of many properties, and then indirectly called CreateThread (...) ;

4._beginthread parameters are less;

3. AfxBeginThread ()

The interface provided by MFC provides two different types of thread generation, worker thread and user interface thread, and can easily understand user interface thread contains user interface, it has its own message queue, worker thread is used for calculation etc.;

cwinthread* AfxBeginThread (   afx_threadproc pfnthreadproc,             //threaded function pointer, function prototype for UINT _CDECL Fnthread (LPVOID pparam) ;   LPVOID Pparam,//                            thread function parameter   int npriority = thread_priority_normal,   //priority, SetThreadPriority   UINT nstacksize = 0,                      //stack size, unit is bytes, is 0 when the default size is   DWORD dwcreateflags = 0,                  //create_suspended: Hangs after creation, 0: runs immediately after creation      lpsecurity_attributes lpsecurityattrs = null  //Pointer to security_attributes structure, NULL indicates default security attribute); Create a worker thread cwinthread* afxbeginthread (   cruntimeclass* pthreadclass,                //Pointer to interface class, inherit from CWinThread   int npriority = Thread_priority_normal,   UINT nstacksize = 0,   DWORD dwcreateflags = 0,   lpsecurity_attributes Lpsecurityattrs = NULL); Create a user interface thread

Description

Header
Afxwin.h

4. Comparison 1. _beginthread and _beginthreadex
    1. On the implementation of _beginthreadex control a _tiddata thread data block, which contains the thread function address, parameters of many properties, and then indirectly called CreateThread (...) ;
    2. The _beginthread parameters are less and have limitations.
2. AfxBeginThread and MFC's CreateThread
    1. AfxBeginThread is created in one step, and then the thread runs immediately
    2. CWinThread::CreateThread is created in two steps, but it holds the thread object and can be reused between successive thread creation and completion of the run (use CreateThread if you want to reuse the thread objects Between successive creation and termination of thread executions)

Second, thread termination

Several ways to end a thread:

    1. Wait for the thread function to finish automatically end
    2. ExitThread () to end the thread itself
    3. TerminateThread (), all threads can end with this method
    4. The parent process shuts down, and the child threads close with it

Only the first method is recommended to end the thread, the other way is defective

Here are a few things that happen during the end:

1. Orderly release of resources (such as operating system allocated resources, C + + class destructor used), return thread exit code, thread kernel object usage count-1

2. Release of operating system-related resources; But like the C + + class does not refactor, causing memory leaks; If you use _beginthreadex to build a thread and use ExitThread or _endthread to release the thread, the thread data block _tiddata the thread is placed on the heap is not released. , memory leaks;

3. The function is an asynchronous function that notifies the operating system of the terminating thread and returns immediately, regardless of whether the system has actually ended the thread. At the same time, the line stacks is not released

4. With Exitprogerss, after the TerminateProcess function closes the process, the process calls TerminateThread to close the thread, such as 3, the thread's stack is not released, and the requested object resource is not released.

1. ExitThread ()
VOID ExitThread (  DWORD dwexitcode);

Description

Header Library
Winbase.h Coredll.lib

Parameters:

Dwexitcode: Specifies the exit code for the thread. You can view the exit code for a thread by GetExitCodeThread

return value: None

Description: After the thread ends, the ExitCode from still_active to the incoming exit code will be converted from the Threads kernel object; corresponding to CreateThread

2. TerminateThread ()
BOOL TerminateThread (  HANDLE hthread,  DWORD dwexitcode);

Description

Header Library
Winbase.h Coredll.lib

Parameters:

Hthread: The thread handle to end
Dwexitcode: Specifies the exit code for the thread. You can view the exit code for a thread by GetExitCodeThread

Return Value: 0 indicates failure, non 0 indicates success;

3. Determine if the thread is finished
BOOL GetExitCodeThread (  HANDLE hthread,  lpdword lpexitcode);
judging bool Isthreadexit (HANDLE hthread) {    bool BRet = false;    DWORD Dwexitcode;    if (GetExitCodeThread (Hthread, &dwexitcode))    {        if (dwexitcode! = still_active)            BRet = true;    }    else    {        //error        err = GetLastError ();           throw err;    }    return bRet; }

Third, the matters needing attention

1. In C + + multithreaded programming, try to use _beginthreadex and _endthreadex instead of other interfaces.

Do not use _beginthread reason:

(1) _beginthread function parameters are not enough, some requirements are not reached,

Do not use _endthread reason:

(1) The _endthread function is also non-parametric, that is, the thread's exit code will be hard-coded to 0;

(2) The function calls CloseHandle before calling ExitThread, and passes in the handle of the new thread. Something like the following code will have an error

DWORD Dwexitcode; HANDLE hthread = _beginthreadex (...); GetExitCodeThread (Hthread, &dwexitcode); CloseHandle (Hthread);

Reasons for not using the CreateThread function:

(1) The standard C/C + + runtime is not originally designed for multi-threaded programming (the standard run-time library appears before the operating system supports thread support), while CreateThread is the operating system interface, which is called by the system when it is invoked, so in order to ensure C/ The program is working properly, and to create a data structure that is associated with each thread of the runtime, _beginthreadex implements this functionality. In other words, creating threads with CreateThread in C + + is extremely unsettling.

Reasons for not using the ExitThread function:

(1) Release of operating system-related resources; But like the C + + class does not refactor, causing memory leaks; If you use _beginthreadex to build threads and use ExitThread or _endthread to release threads, thread data blocks on the heap are thread- Tiddata also not released, memory leaks;

What happens when you use CreateThread in 2.c/c++ programming

When a thread calls a run-time function that requires a thread block of _tiddata, the system first finds the thread data block through thread-local storage (TLS, see the next section), and if the Null,c/c++ runtime assigns and initializes a _tiddata block and associates it with the thread. However, if you use the signal function of the C + + runtime, the entire process will terminate (because the structured exception handling frame SEH is not ready, Rtluserthreadstart will call ExitProcess directly to end the process); Endthreadex to end the thread, the thread data block _tiddata is not freed, causing a memory leak.

Reference:

1. <<windows Core Programming (Fifth edition) >>

2. About _beginthreadex, _beginthread and CreateThread

3. MFC Multithreading and Thread synchronization

4. MSDN

The following sections describe the APIs for creating and removing threads for Windows platforms and their differences, as described in this section:

1. Thread kernel object (OS interface CreateThread internal implementation)

2. Thread Block _tiddata (Implementation _beginthreadex and _beginthread of the C + + runtime Library)

3. Thread End _endthreadex

The following are respectively

One, thread kernel object

When a thread is created, a thread kernel object (assigned to the address space of the process) is created first, such as a context (a data structure) and some statistics, including:

1. Register SP: The address of the thread function pointer to the stack

2. Register IP: Point to the loaded NTDLL.dll Rtluserthreadstart function address

3.Usage Count: Reference count, initialized to 2

4.Suspend count: Pending number, initialized to 1.

5.ExitCode: Exit code, thread at run time is still_active (and initialized to this value)

6.Signaled: Initialize to non-triggered state

Rtluserthreadstart (...)

The function prototypes are as follows:

The Rtluserthreadstart function is where the thread really starts executing, because the new thread's instruction pointer is pointing to the function. The Rtluserthreadstart function prototype makes you think it receives two parameters, but that is not true, which simply means that it is called from another function. The new thread only takes effect here and starts executing.
The Rtluserthreadstart function is thought to be called from another function because it obtains two parameters. But the way to get these parameters is because the operating system writes these values directly to the thread's stack (the way in which parameters are usually passed to the function).
Note that some CPU architectures use CPU registers to pass parameters, not stacks. For these schemas, the system correctly initializes the appropriate registers before agreeing to the thread to execute the Rtluserthreadstart function.
(in 32-bit Windows, the BaseThreadStart function instead of the Rtluserthreadstart function in 64-bit Windows, The BaseThreadStart function is derived from the Kernel32.dll component, and the Rtluserthreadstart function function is derived from the NTDLL.dll component)

The Rtluserthreadstart function is where the thread really starts executing, in the function

(1) Set up a structured exception handling SEH frame around the thread function

(2) When the thread function returns, call ExitThread and pass in the thread function return value as a parameter. The usage count of the thread kernel object is decremented, and then the thread stops executing.

(3) If an unhandled exception occurs during execution, call the Exitprogress () in the exception handling block to close the process

When a program runs, a main thread is generated, and then Rtluserthreadstart begins execution, invoking the code of the C + + runtime, which initializes and then accesses your program entry function (_tmain,_twinmain, etc.); When the entry function returns The run-time startup code calls ExitProcess to end the process.

So using CreateThread to generate a line thread executes has two steps

(1) Generate thread kernel object and initialize

(2) Rtluserthreadstart run thread function pointed to by kernel object

Second, thread data block _tiddata

A thread data block is a data structure maintained by the _beginthreadex function that stores some thread-related information. Let's take a look at _beginthreadex's source code (VS2008 is stored in C:\Program Files\Microsoft Visual Studio 9.0\vc\crt\src\threadex.c):

_mcrtimp uintptr_t __cdecl _beginthreadex (void *security, unsigned stacksize, unsigned (__clr_or_st        D_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-&GT;_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 are passed to CreateThread * * if (Thrda        DDR = = 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, C Reateflag, (Lpdword) thrdaddr)) = = (uintptr_t) 0) {err = Getl                Asterror (); Goto ErroR_return;        }/* * Good return */return (THDL); /* * Error return */error_return:/* * Either ptd is NULL, or it points to the No-longer-ne         Cessary block * calloc-ed for the _tiddata struct which should now is 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 () r         Eturns-1 for failure.        */if (err! = 0L) _dosmaperr (err); Return ((uintptr_t) 0);}

The two parts of which are marked red and bold are the emphasis, that is, the first initialization of a thread data block (_ptiddata ptd), the thread function address and parameters are set to the thread data block, the block is allocated on the heap. After calling the CreateThread function to create the thread, be aware of the arguments passed in the function, that is, the function to be run _threadstartex (note that it is not a thread function), whose parameters are the thread data block (LPVOID) ptd

The function of _threadstartex is

1. Associate the new thread with the memory data block (__fls_setvalue, which is the operating system function, the so-called thread local storage (thread locally Storage, TLS))

2. Call _callthreadstartex to execute and terminate real thread functions

Static unsigned long WINAPI _threadstartex (void * ptd) {_ptiddata _ptd;        /* Pointer to per-thread data */* Initialize flsgetvalue function pointer */__set_flsgetvalue (); /* * Check if PTD is initialised during Thread_attach call to DLL mains * * if (_PTD = (_ptiddata ) __fls_getvalue (__get_flsindex ())) = = NULL) {/* * Stash the pointer to the Per-thread data Stucture in TLS */if (!__fls_setvalue (__get_flsindex (), ptd)) ExitThread (getlaste            Rror ()); /* * Set the thread ID field--parent thread cannot set it after * CreateThread () returns since t             He child thread might has 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; _ptd->_thandle = ((_ptiddata) ptd)->_thandle; #if defined (_M_CEE) | | Defined (Mrtdll) _ptd->__initdomain= ((_ptiddata) ptd)->__initdomain; #endif/* defined (_M_CEE) | |            Defined (mrtdll) */_freefls (PTD);        PTD = _PTD;  }/* * Call FP initialization, if necessary */#ifndef mrtdll#ifdef crtdll _fpclear (); #else        /* Crtdll */if (_fpmtinit! = NULL && _isnonwritableincurrentimage ((pbyte) &_fpmtinit))        {(*_fpmtinit) (); } #endif/* Crtdll */#endif/* Mrtdll */#if defined (_M_CEE) | |        Defined (mrtdll) DWORD domain=0;        if (!_getdomain (&domain)) {exitthread (0); } if (Domain!=_ptd->__initdomain) {/* need to transition to caller ' s domain and startup there* /:: Msclr::call_in_appdomain (_ptd->__iNitdomain, _callthreadstartex);        return 0L; } #endif/* defined (_M_CEE) | |        Defined (mrtdll) */_callthreadstartex ();         /* * Never executed! */return (0L);}
static void _callthreadstartex (void) {    _ptiddata ptd;           /* Pointer to thread ' s _tiddata struct    /*//* must always exist at this point *    /ptd = _GETPTD ();        /* * Guard call to user code with a _try-_except statement to        * Implement runtime errors and signal        support *    /__try {            _endthreadex (                
*) (void *)) (((_ptiddata) ptd)->_initaddr) (((_ptiddata) ptd)
_initarg));    }    __except (_xcptfilter (GetExceptionCode (), GetExceptionInformation ()))    {            /                * * should never reach here< c18/>*/            _exit (GetExceptionCode ()),    }/* End of _try-_except */}

The _callthreadstartex function functions as follows:

1. Run true thread function as superscript red place

2. Pass the return value of the real thread function run out as the return code to _endthreadex end the thread

At this point, _beginthreadex is finished running.

Here _callthreadstartex call _endthreadex directly delete the thread, instead of fallback to _threadstartex, and then to Rtluserthreadstart, if directly returned, the thread data block is not deleted, will cause memory leaks.

Summarize the running process of the _beginthreadex

1. Mr. Cheng and initializes the _tiddata memory block, passing in the thread function address and parameters

2. Call the CreateThread build thread and use the Rtluserthreadstart function to run the thread function (but the function to run is _threadstartex, the parameter is the thread block address)

3._threadstartex the thread-local storage (TLS) binds the threading data block to the running thread

4._threadstartex calls _callthreadstartex, runs the real thread function, and ends with _endthreadex when the true thread function returns correctly, and returns 0 if an error occurs;

The following is a detailed description of _tiddata, which can be consulted under (vs2008,c:\program Files\Microsoft Visual Studio 9.0\vc\crt\src\mtdll.h).

View CodeThird, thread termination

The _callthreadstartex function uses _endthreadex to terminate the thread, as shown in the following code:

void __cdecl _endthreadex (        unsigned retcode        ) {        _ptiddata ptd;           /* Pointer to thread ' s _tiddata struct        *         /* * Call FP termination, if necessary *         /#ifdef crtdll        _fpclear ( ); #else/  * Crtdll */        if (_fpmtterm! = NULL &&            _isnonwritableincurrentimage ((pbyte) &_ Fpmtterm))        {            (*_fpmtterm) ();        } #endif  /* Crtdll *        /ptd = _getptd_noexit ();        if (PTD) {/* * free up '             _tiddata structure & its subordinate buffers             *      _freeptd () would also CL Ear the value for this thread             * of the      FLS variable __flsindex.             *            /_FREEPTD (PTD);        }         /* * Terminate the thread *        /ExitThread (retcode);}

Therefore, the functions of _endthreadex are as follows:

1. Delete the thread data block associated with the thread

2. Call ExitThread (relative to CreateThread) to terminate and pass the exit code

Reference:

<<windows Core programming version Fifth >>

Translation of the "Rtluserthreadstart function" in Windows via C + +

_beginthreadex Creating multithreaded Interpretations

VC Source: C:\Program Files\Microsoft Visual Studio 9.0\vc\crt\src\mtdll.h | | THREADEX.C (VS2008)

http://blog.csdn.net/flyingleo1981/article/details/52788150

Windows thread Health (illustrated)

Related Article

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.