线程等待
为什么需要线程等待?
- 已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。
- 创建新的线程不会复⽤刚才退出线程的地址空间。
线程退出也需要保存自己的退出返回值,因此线程也需要等待。只有线程处于joinable状态,这个线程才会被阻塞(joinable线程默认属性)。
功能:等待线程结束
原型
int pthread_join(pthread_t thread, void **value_ptr);
参数
thread:线程ID
value_ptr:它指向⼀个指针,后者指向线程的返回值
返回值:成功返回0;失败返回错误码
调⽤该函数的线程将挂起等待,直到id为thread的线程终⽌。thread线程以不同的⽅法终⽌,通过pthread_join得
到的终⽌状态是不同的,总结如下:
- 1. 如果thread线程通过return返回,value_ ptr所指向的单元⾥存放的是thread线程函数的返回值。
- 2. 如果thread线程被别的线程调⽤pthread_ cancel异常终掉,value_ ptr所指向的单元⾥存放的是常数PTHREAD_ CANCELED。
- 3. 如果thread线程是⾃⼰调⽤pthreadexit终⽌的,valueptr所指向的单元存放的是传给pthread_exit的参数。
- 4. 如果对thread线程的终⽌状态不感兴趣,可以传NULL给value_ ptr参数。
#include <stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<errno.h>
void* thr_start(void* arg)
{
printf("arg:%d\n",(int)arg);
sleep(10);
return NULL;
}
int main()
{
pthread_t tid;
int ret = pthread_create(&tid, NULL, thr_start, (void*)88);
if(ret != 0)
{
printf("cteate pthread error\n");
return -1;
}
sleep(2);
pthread_cancel(tid);//PTHREAD_CANCELED
char* retval;
ret = pthread_join(tid, (void**)&retval);
if(ret == EINVAL)
{
printf(""pthread is not joinable\n");
}
printf("--------------[%d]\n",(int)retval);
return 0;
}
运行结果:
由于是静态图,所以等待过程看不见,不过可以看出,如果thread线程被别的线程调⽤pthread_ cancel异常终掉,value_ ptr所指向的单元⾥存放的是常数PTHREAD_ CANCELED。这个常数的值是-1.
分离线程
- 默认情况下,新创建的线程是joinable的,线程退出后,需要对其进⾏pthread_join操作,否则⽆法释放资源,从⽽造成系统泄漏。
- 如果不关⼼线程的返回值,join是⼀种负担,这个时候,我们可以告诉系统,当线程退出时,⾃动释放线程资源。
线程有一个属性,这个属性可以为-joinable/detach
joinable是线程的默认属性,表示线程退出后需要被等待,获取返回值,允许操作系系统回收资源
detach是需要重新设置的属性,表示线程退出后将直接释放资源,也就意味着线程无法被等待。
线程的这个属性只能选择其一;
int pthread_detach(pthread_t thread);
可以是线程组内其他线程对目标线程进⾏分离,也可以是线程⾃⼰分离:
pthread_detach(pthread_self());
joinable和分离是冲突的,⼀个 线程不能既是joinable⼜是分离的。
#include <stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<errno.h>
void* thr_start(void* arg)
{
pthread_detach(pthread_self());
printf("arg:%d\n",(int)arg);
sleep(10);
return NULL;
}
int main()
{
pthread_t tid;
int ret = pthread_create(&tid, NULL, thr_start, (void*)88);
if(ret != 0)
{
printf("cteate pthread error\n");
return -1;
}
sleep(2);
pthread_cancel(tid);//PTHREAD_CANCELED
char* retval;
ret = pthread_join(tid, (void**)&retval);
if(ret == EINVAL)
{
printf("pthread is not joinable\n");
}
printf("--------------[%d]\n",(int)retval);
return 0;
}
很明显,当把子线程的属性重新设置后,就不在是一个需要等待的线程,所以用线程等待函数pthread_join失败。