一、 pthread_detach
int pthread_detach(pthread_t thread);
创建一个线程默认的状态是joinable, 如果一个线程结束运行但没有被join,则它的状态类似于进程中的Zombie Process,即还有一部分资源没有被回收,所以创建线程者应该调用pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源(类似于wait,waitpid)。
但是调用pthread_join(thread_id)后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此,比如在Web服务器中当主线程为每个新来的链接创建一个子线程进行处理的时候,主线程并不希望因为调用pthread_join而阻塞(因为还要继续处理之后到来的链接),这时可以在子线程中加入代码
pthread_detach(pthread_self())
或者父线程调用
pthread_detach(thread_id)(非阻塞,可立即返回)
这将该子线程的状态设置为detached,则该线程运行结束后会自动释放所有资源。
二、pthread_join
int pthread_join(pthread_t thread, void **retval);
join是三种同步线程的方式之一。另外两种分别是互斥锁(mutex)和条件变量(condition variable)。
调用pthread_join()的线程会阻塞,直到指定的线程返回,调用了pthread_exit(),或者被取消。
一个线程对应一个pthread_join()调用,对同一个线程进行多次pthread_join()调用是逻辑错误。
如果线程简单地返回,那么rval_ptr被设置成线程的返回值,参见范例1;
如果调用了pthread_exit,则可将一个无类型指针返回,在pthread_join中对其进行访问,参见范例2;
如果线程被取消,rval_ptr被设置成PTHREAD_CANCELED。
如果我们不关心线程的返回值,那么我们可以把rval_ptr设置为NULL。
范例1:
#include <pthread.h>
#include <string.h>
void *thr_fn1(void *arg)
{
printf("thread 1 returning.\n");
return((void *)1);
}
void *thr_fn2(void *arg)
{
printf("thread 2 exiting.\n");
return((void *)2);
}
int main()
{
pthread_t tid1,tid2;
void *tret;
pthread_create(&tid1,NULL,thr_fn1,NULL);
pthread_create(&tid2,NULL,thr_fn2,NULL);
pthread_join(tid1,&tret);
printf("thread 1 exit code %d\n",(int)tret);
pthread_join(tid2,&tret);
printf("thread 2 exit code %d\n",(int)tret);
exit(0);
}
运行结果:
thread 1 returning.
thread 1 exit code 1.
thread 2 exiting.
thread 2 exit code 2.
范例2:
#include <stdio.h>
#include <pthread.h>
void thread1(char s[])
{
printf("This is a pthread1.\n");
printf("%s\n",s);
pthread_exit("Hello first!"); //结束线程,返回一个值。
}
void thread2(char s[])
{
printf("This is a pthread2.\n");
printf("%s\n",s);
pthread_exit("Hello second!");
}
int main(void)
{
pthread_t id1,id2;
void *a1,*a2;
int i,ret1,ret2;
char s1[]="This is first thread!";
char s2[]="This is second thread!";
ret1=pthread_create(&id1,NULL,(void *) thread1,s1);
ret2=pthread_create(&id2,NULL,(void *) thread2,s2);
pthread_join(id1,&a1);
printf("%s\n",(char*)a1);
printf("This is the main process.\n");
pthread_join(id2,&a2);
printf("%s\n",(char*)a2);
return (0);
}
运行结果:
This is a pthread1.
This is a pthread2.
This is first thread!
This is second thread!
Hello first!
This is the main process.
Hello second!
一般情况下,进程中各个线程的运行都是相互独立的,线程的终止并不会通知或影响其他线程,终止的线程所占用的资源也并不会随着线程的终止而释 放。正如进程之间可以用wait()系统调用来同步终止并释放资源一样,线程之间也有类似机制,那就是pthread_join()函数。
pthread_join(th)的调用者将挂起并等待th线程终止,retval是pthread_exit()调用者线程(th)的返回值,如果thread_return不为NULL,则*thread_return=retval。
需要注意的是一个线程仅允许唯一的一个线程使用 pthread_join()等待它的终止,并且被等待的线程应该处于可join状态,即非DETACHED状态
一个可join的线程所占用的内存仅当有线程对其执行了pthread_join()后才会释放,因此为了避免内存泄漏,所有线程的终止,要么已设为DETACHED,要么就需要使用pthread_join()来回收。
主线程用pthread_exit还是return:
用pthread_exit只会使主线程自身退出,产生的子线程继续执行;用return则实际调用_exit(),故所有线程都退出。