Original source: http://www.cnblogs.com/lidabo/p/5514100.html
Recently, I heard that pthread_create will cause memory leaks, it is incredible, so the POSIX (NPTL) thread creation and destruction are analyzed. Analysis results: if used incorrectly, it does cause a memory leak. root cause : Pthread_create The thread created by default is detached. Prevention: Either create a detached thread, either before the thread's start_routine ends detached, or the join analysis process is as follows: 1. View Pthread_create source Code, The core code is as follows (NPTL/PTHREAD_CREATE.C):
Click (here) to collapse or open int __pthread_create_2_1 (NEWTHREAD, ATTR, START_ROUTINE, ARG) pthread_t *newthread; const pthread_attr_t *attr; void * (*start_routine) (void *); void *arg; { STACK_VARIABLES; const struct pthread_attr *iattr = (struct pthread_ attr *) attr; if (Iattr == null) /* is this the best idea? on numa machines This could mean accessing Far-away memory. */ iattr = &default_attr; struct pthread *pd = null; int err = Allocate_stack (iattr, &PD);//Allocate memory for TCB if (__builtin_expect (Err != 0, 0)) /*  Something went wrong. maybe a parameter of the Attributes is Invalid or we could not allocate memory. */ return err; ... err = Create_thread (PD, IATTR, Stack_variables_args);//formally Create thread 2. View CREATETHREAD.C (NPTL/SYSDEPS/PTHREAD/CREATETHREAD.C)
Click (here) to collapse or open the static int create_thread (struct pthread *pd, const struct, pthread_attr *attr, Stack_variables_par MS) {#ifdef TLS_TCB_AT_TP assert (PD->HEADER.TCB!= NULL); #endif//... int res = Do_clone (PD, attr, Clone_flags, start_thread, Stack_variables_args, 1);//clone a Process 3. Then see Start_thread (NPTL/PTHREAD_CREATE.C) did What
Click (here) to collapse or open static int start_thread (void *arg) { struct pthread *pd = ( struct pthread *) arg; ... /* run the code the user provided. */#ifdef CALL_THREAD_FCT & nbsp; thread_setmem (pd, result, call_thread_fct (PD)); #else thread_setmem (PD, result, Pd->start_routine (Pd->arg)); // Officially start the execution of the thread and wait for execution to complete #endif//... if (is_detached (PD)) /* Free the TCB. */ __FREE_TCB (PD);//If the detached flag is set, the content of the TCB is released, otherwise the direct return else if (__builtin_expect Cancelhandling & Setxid_bitmask, 0) { /* Some other thread might call any of the S Etxid functions and expect us to reply. in This case wait until we did that. */ do lll_futex_wait (&pd->setxid_futex, 0, LLl_private); while (pd->cancelhandling & Setxid_bitmask); /Reset The value so this stack can be reused. */ Pd->setxid_futex = 0; } from the above procedure, we can see that if the detached flag is not set when the thread is created, TCB memory will never be released Next, let's look at what Pthread_detach (npth/pthread_detach.c) did
Click (here) to collapse or open the int pthread_detach (TH) pthread_t th; { struct pthread *pd = (struct pthread *) th; /* make sure the descriptor is valid. */ if (invalid_not_terminated_td_p (PD)) /* not a valid thread handle. */ return esrch; int result = 0; /* mark the thread as detached. */ if (Atomic_compare_and_exchange_bool_acq (&pd->joinid, pd, null)) { /* there are two possibilities here. first, the thread might Already be detached. in this case we return einval. otherwise there might already be a waiter. the standard does Not mention What happens in this case. */ if ( is_detached (PD)) result = EINVAL; } else /* check whether the thread terminated Meanwhile. in this case we will just free the TCB. */ if ((pd->cancelhandling & exiting_bitmask) != 0) /* note that the CODE IN __FREE_TCB makes sure each Thread control block is freed only once. */   __FREE_TCB (PD);//After a series of fault-tolerant judgment, direct release TCB occupied memory return result; } Finally, let's take a look at what Pthread_join (NPTL/PTHREAD_JOIN.C) did
Click (here) to collapse or open the int pthread_join (threadid, thread_return) pthread_t ThreadID; void **thread_return; { struct pthread *pd = (struct pthread *) threadid; /* make Sure the descriptor is valid. */ if (invalid_not_terminated_td_p (PD)) /* not a valid thread handle. */ return ESRCH; /* is the thread joinable? */ if (is_detached (PD)) /* we cannot wait for The thread. */ return einval; struct pthread *self = thread_self; int result = 0; /* during The wait we change to asynchronous cancellation. if we are canceled the thread we are WaitiNg for must be marked as un-wait-ed for again. */ pthread_cleanup_push (Cleanup, &pd->joinid); /* switch to asynchronous cancellation. */ int oldtype = CANCEL_ASYNC (); if (pd == self | | (SELF->JOINID == PD && (pd->cancelhandling & (Canceling_bitmask | canceled_bitmask | exiting_ Bitmask | terminated_bitmask)) == 0) && ! cancel_enabled_and_canceled (self->cancelhandling)) /* this is a Deadlock situation. the threads are Waiting for each &nbSp;other to finish. note that this is a ' may ' error. to be 100% sure we catch This error we would have to lock the data structures but it is not necessary. in the Unlikely case that two threads are really caught in This situation they would deadlock. it is the programmer ' s Problem to figure this out. */ result = edeadlk; /* wait for the Thread to finish. if it is already Locked something is wrong. there can only one waiter. */ else if (__builtin_expect (atomic_compare_and_exchange_bool_acq (&pd->joinid, Self, NULL), 0) /* there is already somebody waiting for the thread. */ result = EINVAL; else /* wait for the child. */ lll_wait_tid (Pd->tid); /* restore cancellation mode. */ CANCEL_RESET (Oldtype); /* remove the handler. */ pthread_cleanup_pop (0); if (__builtin_expect (RESULT ==&NBsp;0, 1)) { /* we mark the thread as terminated and as joined. */ pd->tid = -1; /* store The return value if the caller is interested . */ if (Thread_return!= NULL)
*thread_return = pd->result;//Set return value
/* Free the TCB. */
__FREE_TCB (PD);/release TCB occupy memory} return result; In summary, if you want to ensure that there is no memory leak after creating the thread, you must use the following methods to standardize the pthread_create:method One, creating the detached thread
Click (here) to collapse or open void run () { return; Int main () { pthread_t thread; pthread_attr_t attr; pthread_attr_init ( &attr ); pthread_attr_setdetachstate (&attr,1); pthread_create (&thread, &attr, run, 0); // ...... return 0; } method Two, or before the start_routine end of the thread thread detached
Click (here) to collapse or open void run () { pthread_detach (Pthread_self ()); } Int main () { pthread_t thread; pthread_create (&thread, NULL, run, 0); //...... &nbsP; return 0; } method Three, main thread uses Pthread_join
Click (here) to collapse or open void run () { return; Int main () { pthread_t thread; pthread_create (&thread, NULL, run, 0);  &NBSp; //...... Pthread_join (thread,null); return 0; }