Thread self-termination causes an abnormal preconditionation of thread internal objects?

xiaoxiao2021-03-06  60

At first, the main thread A is existing as a dialog box ctestdlg. Now, starting a new thread b in the member function on the ctestdlg on OnStartTTARTTTHREAD function, a CString local variable stra (Note 1) as a thread B work function parameter PPAram, ctestdlg Member function OneendThread is used to set abort line B, see the sample code below:

... thread a (main thread) ctestdlg :: onStartthread () {cstring stra! // Stra as local variable transmission lpvoid pParam = (lpvoid) & straw; cwinthread * m_pthread = :: afxbeginthread (& Threadproc, pparam);} void cmsitestdlg :: Oneendthread () {g_bstopthread = true;

... Thread Buint ThreadProc (LPVOID PPARAM) {CSTRING STRB = * (CString *) PPAram; // Note: Reference count of heap data plus 1, this will result in memory leakage! CString strc = "here's in thread b"; // thread B work function CString partial variable, which may also generate memory leakage!

While (! g_bstopthread) {if (g_bstopthread == true) {afxendthread (0, true); // Forced aborting thread B, only clear the stack data in the thread, but will not empty the stack data! // Return 0; // Recommended! Normal returns 0, so that STRB can sect a normal design, minimize the reference count of the heap data, and finally make the stack data to be released. }

SLEEP (200); // Analog thread work} return 0; // Normal return 0} Here, thread a and thread b runs non-synchronous, that is, thread A does not need to wait for the completion of thread B, start thread B, first Enter the work function of thread B:

Tip: If you know the CString reference count, you should know that the copy between the CString object is done by the reference count mechanism for the stack data. The data structure of the stack data is as follows: struct cstringdata {long nrefs; // reference count Country INT NDATALEENGTH; // length of data (incruding Terminator) Data length INLLOCLENGTH; // length of allocation actually allocated in the heap / / Tchar data [Nalloclength]

TCHAR * DATA () // tchar * to managed Data data of the first pointer {RETURN (TCHAR *) (THIS 1);}; STRA as part variables in a function of the main thread A, When initialization, first allocate data in the heap, then initialize the reference count NREFS of the heap data to 1, and the string is transmitted to the working function of the thread B, and assigns the value to STRB, and the stack data in STRA is not Re-replicate a copy of STRB in memory, but only the reference number of the original heap data is added 1, and finally, the reference count of the stack data count NREFS is 2. Back to thread a, thread a will be partially variable STRA sectors, first call the InterlockDecrement (refer to 2) function during the sectoral process, reduce the reference number NREFS of the data 1 and return to the reducing reference count value, if NREFS is less than or equal to 0, call FreeData to empty the stack data. Here, the reference count NREFS of the heap data is equal to 2, after 1 NREFS is equal to 1, so the stack data is not released, which produces potential memory leakage! Return to thread b, if the thread B is ended normally (ie, returning from the work function), the strb destructor will be analyzed, according to the above, the data reference count NREFS is equal to 1, and then calls InterLockDecrement again to count NREFS minus 1 NREFS is equal to 0, therefore, call freeData to empty the stack data, this will not exist in memory leak; if the thread B is running, the oneendthread function is called in the main thread A, and finally calls the AFXEndThread in the thread b. Its itself, what happened next? Internal debug mode to trace AfxEndThread: void AFXAPI AfxEndThread (UINT nExitCode, BOOL bDelete) {# ifndef _MT nExitCode; bDelete; #else // remove current CWinThread object from memory AFX_MODULE_THREAD_STATE * pState = AfxGetModuleThreadState (); CWinThread * pThread = pState- > m_pCurrentWinThread; if (pThread = NULL!) {ASSERT_VALID (pThread); ASSERT (! pThread = AfxGetApp ()); (! pThread-> m_lpfnOleTermOrFreeLib = NULL) // cleanup OLE if required if (* pThread-> m_lpfnOleTermOrFreeLib) ( TRUE, FALSE;

IF (bdlete) pthread-> delete (); pstate-> m_pcurrentwinthread = null;}

// allow cleanup of any thread local objects afxtermthread ();

// allow c-runtime to cleanup, and exit the thread _endthreadex (nexitcode); # Endif //! _ MT} AFXEndThread By calling pthread-> delete () makes thread B's stack clearance (start thread B, the thread is thread) B Assign a stack: Reference 3), then clear all the stacks allocated in the thread B work function, including StrB, but this will not cause strbs to be designed normally, and cannot reduce the reference number of the heap data 1, and eventually do not release the stack data, trigger memory leakage! In response, I made another test and prove that STRB did not be analyzed by normal, see the sample code 2: ... thread a (main thread) ctestdlg :: onstartthread () {cstring straa = "The Stra will be leak ";! // strA passed as a local variable LPVOID pParam = (LPVOID) & strA; CWinThread * m_pThread = :: AfxBeginThread (& ThreadProc, pParam); WaitForSingleObject (m_pThread-> m_hThread, INFINITE);} void CMsiTestDlg :: OnEndThread () {G_bstopthread = true;

... Thread Buint ThreadProc (LPVOID PPARAM) {CSTRING STRB = * (CString *) PPAram; // Note: Reference count of heap data plus 1, this will result in memory leakage! CString strc = "here's in thread b"; // thread B work function CString partial variable, which may also generate memory leakage!

While (! g_bstopthread) {if (g_bstopthread == true) {afxendthread (0, true); // Forced abort, only empty the stack data in the thread, but will not empty the pile data! // Return 0; // Recommended! Normal returns 0, so that STRB can sect a normal design, minimize the reference count of the heap data, and finally make the stack data to be released. } G_bstopthread = true; // Only enter once, the next time it ends

Sleep (200); // Analog thread work} return 0; // Normal Returns 0} Comparison Example 1 Code, add two lines of code (bold display). g_bstopthread = true, enabling thread b to end immediately at the next cycle; WaitForsingleObject (m_pthread-> m_hthread, infinite), waiting for thread B to end. Set the breakpoint at the end of OnStartThread} number, press F11 to enter STRA's destructor: cstring :: ~ cstring () // free any attachd data {i (getData ()! = _AfxDatanil) {i (InterlockedDecrement (& getData) ) -> NREFS) <= 0) FREEDATA ()}} The getData () -> NREFS value is still 2 (see above, string in thread A, three times in the thread A). Quoted with the same heap data), this means that after the thread b is terminated, it is not correctly destructed with STRB, and thus does not minimize the reference count of the heap data. After executing the reference count is reduced, check the getData () -> NREFS value of 1, not entering the freedata (getData ()) line to release the stack data, generate memory leakage! As for why thread self-ending does not make thread internal objects normally, I need to further consult relevant information, will make up. In fact, even if the thread b does not quote the stack data in thread A, if the STRC is added to the working function of the thread B and the value is assigned to it, the AFXendThread forcibly abort the thread can also cause the STRC to be despotected, and memory Hand leak! In summary, call AFXEndthread or TerminateThread and other functions of thread termination in the thread, which is not safe, and the correct way is to be stopped, returning directly from the working thread function to correctly release the stack! Note: 1. STRA can also be set to global shared variables or static variables for example test. Reference: 1. 9CBS Document: Stack of Win32 Environment (1) 2. MSDN Help 3. About 1 Nice Comments: 2003.11.9 14:21

XLEEP comments

I agree with the view of a friend, the pile is a pile, the stack is the stack.

A lot of domestic written books or translations are written in a stack, and the stack is also written to a stack. In fact, both are different.

The landlord wrote a stack. The stack is a single memory that thread first operating system assigned to this thread (the landlord has already speaking very detailed). When a part of your function is large, such as approaching 1M, stack (stack) overflows.

Stacks like Mayax, divided by defaults, using Delete, New, Malloc, Free in C , C to operate the default heap (default is 1MB). Stacks will not overflow. Only allocation failed. For example, PVOID PV = Malloc (0x100000); when Malloc sees that there is no big memory in the default heap, it will return null, which is the failed assignment. Of course, the default pile is not enough, in Win32, you can use HeapCreate to create a secondary heap, with Heapalloc to assign a stack memory, with HeapFree to release the stack memory, with HeapDestroy to destroy this auxiliary.

It is recommended to see the "Windows Core Programming" of Jeffrey Richter to this thing, this is very clear about Win32's memory management, but the Chinese translator is translated into stacks in this book, putting Heap Also translated into stacks. Also worth mentioning is that the global variable is not placed in a heap but placed in the PE file. When the operating system loader, the data section of the PE file is mapped to where, the global variable is in that memory inside. This can you understand the PE structure.

转载请注明原文地址:https://www.9cbs.com/read-82446.html

New Post(0)