Linux下多线程编程时,线程有两种属性,一种是joinable,一种是detached。
如果是joinable的线程,那么必须使用pthread_join()来等待线程结束,否则线程所占用的资源不会得到释放,会造成资源泄露。
其他线程或父线程如果没有调用pthread_join去做相关资源的释放(pthread id等),该线程运行结束后资源就得不到释放,所在进程的pthread id数目就可能会累积到达最大数目PTHREAD_THREADS_MAX,此时该进程就不能再创建线程了,因为pthread id等资源被用光了,这是在多线程编程中很常见的bug之一。
一个joinable线程,只能有一个pthread_join()来等待结束,如果有多个,则只有第一个执行到的有效,其他的都会直接返回,具体错误信息由pthread_join()函数的返回值返回。
pthread_create()函数默认创建的线程是joinable属性的,或者也可以使用下述代码显示的将线程设为joinable属性:
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&tid, &attr, callback, (void *)context);
如果想创建一个线程,但又不想使用pthread_join()等待该线程结束,那么可以创建一个detached的线程。detached属性的线程,在结束的时候,会自动释放该线程所占用的资源。
detached不需要,也不能使用pthread_join()来等待线程结束。
可以用如下代码在来设置并创建detached线程:
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, callback, (void *)context);
包含两种属性线程的代码示例:
#include
#include
#include
#include
#include
pthread_t pid_joinable;
pthread_t pid_detached;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int count;
void printids(const char *s)
{
pid_t pid;
pthread_t tid;
pid = getpid();
tid = pthread_self();
printf("%s pid %u tid %u (0x%x)\n", s, (unsigned int)pid,
(unsigned int)tid, (unsigned int)tid);
}
void *cb_joinable(void *arg)
{
printids("New thread joinable begin");
printids("New thread joinable:");
int i=0;
for ( ; i<5; ++i)
{
pthread_mutex_lock(&mutex);
printf("joinable runing %d\n", count++);
pthread_mutex_unlock(&mutex);
sleep(1);
}
return ((void*)123);
}
void *cb_detached(void *arg)
{
printids("New thread detached begin");
printids("New thread detached:");
int i=0;
for ( ; i<10; ++i)
{
pthread_mutex_lock(&mutex);
printf("detached runing %d\n", count++);
pthread_mutex_unlock(&mutex);
sleep(1);
}
return ((void*)456);
}
int main(void)
{
int err;
count = 0;
pthread_mutex_init(&mutex, NULL);
err = pthread_create(&pid_joinable, NULL, cb_joinable, NULL);
if ( 0 != err )
{
printf("can't create joinable thread: %s\n", strerror(err));
}
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
err = pthread_create(&pid_detached, &attr, cb_detached, NULL);
if ( 0 != err )
{
printf("can't create detached thread:%s\n", strerror(err));
}
pthread_attr_destroy (&attr);
int **ret;
err = pthread_join(pid_joinable, (void**)ret);
if ( err == 0 )
{
printf("joinable return %d\n", *ret);
}
else
{
printf("can't pthread_join pid_joinable thread: %s\n", strerror(err));
}
err = pthread_join(pid_detached, (void**)ret);
if ( err == 0 )
{
printf("pid_detached return %d\n", *ret);
}
else
{
printf("can't pthread_join pid_detached thread: %s\n", strerror(err));
}
pthread_mutex_destroy(&mutex);
return 0;
}
编译运行:
g++ thread.cpp -o test -pthread
./test
输出结果如下所示:
New thread joinable begin pid 3330 tid 85509888 (0x518c700)
New thread joinable: pid 3330 tid 85509888 (0x518c700)
joinable runing 0
New thread detached begin pid 3330 tid 77117184 (0x498b700)
New thread detached: pid 3330 tid 77117184 (0x498b700)
detached runing 1
joinable runing 2
detached runing 3
detached runing 4
joinable runing 5
joinable runing 6
detached runing 7
detached runing 8
joinable runing 9
detached runing 10
joinable return 123
can't pthread_join pid_detached thread: Invalid argument
从结果可以看出,main函数阻塞到了这行代码:
err = pthread_join(pid_joinable, (void**)ret);
等线程工作完成后,通过此处对线程资源做了释放。
而pid_detached线程为detached属性,所以强行调用pthread_join函数会报错:
can't pthread_join pid_detached thread: Invalid argument