linux pthread detach 和 joinable属性
这两天在看Pthread 资料的时候,无意中看到这样一句话(man pthread_detach):
Either pthread_join(3) or pthread_detach() should be called for each thread that an application creates, so that system resources for the thread can be released. (But note that the resources of all threads are freed when the process terminates.)
也就是说:每个进程创建以后都应该调用pthread_join 或 pthread_detach 函数,只有这样在线程结束的时候资源(线程的描述信息和stack)才能被释放.
之后又查了pthread_join?但是没有明确说明必须调用pthread_join 或 pthread_detach.
但是再查了 Pthread for win32?pthread_join
When a joinable thread terminates, its memory resources (thread descriptor and stack) are not deallocated until another thread performs pthread_join on it. Therefore,?pthread_join must be called? once? for?each joinable thread created to avoid?memory leaks.
?才知道如果在新线程里面没有调用pthread_join 或 pthread_detach会导致内存泄漏, 如果你创建的线程越多,你的内存利用率就会越高, 直到你再无法创建线程,最终只能结束进程。?解决方法有三个:1. ? 线程里面调用?pthread_detach(pthread_self())?这个方法最简单2.?在创建线程的设置PTHREAD_CREATE_DETACHED属性3.?创建线程后用?pthread_join()?一直等待子线程结束。?下面是几个简单的例子1.?调用??pthread_detach(pthread_self())#include <stdio.h>#include <stdlib.h>#include <pthread.h>void *PrintHello(void){pthread_detach(pthread_self());int stack[1024 * 20] = {0,};//sleep(1);long tid = 0;//printf(“Hello World! It’s me, thread #%ld!\n”, tid);//pthread_exit(NULL);}int main (int argc, char *argv[]){pthread_t pid;int rc;long t;while (1) {printf(“In main: creating thread %ld\n”, t);rc = pthread_create(&pid, NULL, PrintHello, NULL);if (rc){printf(“ERROR; return code from pthread_create() is %d\n”, rc);//exit(-1);}sleep(1);}printf(” \n— main End —- \n”);pthread_exit(NULL);}2.?在创建线程的设置PTHREAD_CREATE_DETACHED属性#include <stdio.h>#include <stdlib.h>#include <pthread.h>void *PrintHello(void){int stack[1024 * 20] = {0,};//pthread_exit(NULL);//pthread_detach(pthread_self());}int main (int argc, char *argv[]){pthread_t pid;int rc;long t;while (1) {printf(“In main: creating thread %ld\n”, t);pthread_attr_t attr;pthread_t thread;pthread_attr_init (&attr);pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);rc = pthread_create(&pid, &attr, PrintHello, NULL);pthread_attr_destroy (&attr);if (rc){printf(“ERROR; return code from pthread_create() is %d\n”, rc);//exit(-1);}sleep(1);}printf(” \n— main End —- \n”);pthread_exit(NULL);}3. 创建线程后用?pthread_join() 一直等待子线程结束。?#include <stdio.h>#include <stdlib.h>#include <pthread.h>void *PrintHello(void){int stack[1024 * 20] = {0,};//sleep(1);long tid = 0;//pthread_exit(NULL);//pthread_detach(pthread_self());}int main (int argc, char *argv[]){pthread_t pid;int rc;long t;while (1) {printf(“In main: creating thread %ld\n”, t);rc = pthread_create(&pid, NULL, PrintHello, NULL);if (rc){printf(“ERROR; return code from pthread_create() is %d\n”, rc);//exit(-1);}pthread_join(pid, NULL);sleep(1);}printf(” \n— main End —- \n”);pthread_exit(NULL);}?最近解决了一个隐蔽的内存泄漏问题,我们的进程是HA模式,用户不停的切换,会导致内存不停的增长,切换一次,再切回来内存便增加8M左右。原因就是是pthread_create后的僵死线程没有释放导致的内存持续增长。
?
pthread_create (&thread, NULL, &thread_function, NULL);?就这么写了,参数2没有设置线程结束后自动detach,并且没有使用pthread_join或pthread_detach释放执行结束后线程的空间!
?
Linux man page?里有已经说明了这个问题:
??? When a joinable thread terminates, its memory resources (thread descriptor and stack) are not deallocated until another thread performs pthread_join on it. Therefore,?pthread_join must be called? once? for?each joinable thread created to avoid?memory leaks.
也就说线程执行完后如果不join的话,线程的资源会一直得不到释放而导致内存泄漏!
?
解决办法:
?
创建线程前设置?PTHREAD_CREATE_DETACHED?属性
?pthread_attr_t?attr;
?pthread_t?thread;
?thread_attr_init?(&attr);
?pthread_attr_setdetachstate?(&attr,?PTHREAD_CREATE_DETACHED);
?pthread_create?(&thread,?&attr,?&thread_function,?NULL);
?pthread_attr_destroy?(&attr);
这样就会在线程return/pthread_exit后释放内存。
其实用valgrind检查时会提示pthread_create没有释放的问题,这样的问题也只有在长时间运行时,慢慢积累这一点点的内存才会暴露出来。
?
?
属性值不能直接设置,须使用相关函数进行操作,初始化的函数为pthread_attr_init,这个函数必须在pthread_create函数 之前调用。属性对象主要包括是否绑定、是否分离、堆栈地址、堆栈大小、优先级。默认的属性为非绑定、非分离、缺省1M的堆栈、与父进程同样级别的优先级。
线程的分离状态决定一个线程以什么样的方式来终止自己。在上面的例子中,我们采用了线程的默认属性,即为非分离状态,这种情况下,原有的线程等待 创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。而分离线程不是这样子的,它没有被其 他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。程序员应该根据自己的需要,选择适当的分离状态。设置线程分离状态的函数为pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)。第二个参数可选为PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE_JOINABLE(非分离线程)。