线程等待:
为什么需要线程等待?
1.已经退出的线程,其空间没有被释放,仍然在进程的地址空间内
2.创建新的线程不会复用刚才退出的线程地址空间
我们知道进程内至少有一个线程作为执行单位,当我们进程退出了,意味着我们的线程也退出了。但是进程内有多个线程时,我们只想结束掉其中的某一个线程时,我们该如何做呢?系统为我们提供了下面几种方式:
1.从线程函数中直接调用 return ,这种方法对主线程不适用,从mian函数return相当于调用了exit,结束掉了整个进程。
2.线程可以调用pthread——exit() 终止自己
3.一个线程可以调用 pthread_cancel() 终止同一个进程中的另一个进程
看一下这两个函数的原型:
void pthread_exit(void *value_ptr);
参数:value_ptr:value_ptr 不要指向一个局部变量
返回值:无
----------------------------
int pthread_cancel(pthread_t thread);
参数:thread(线程ID)
返回值: 成功返回0,失败返回错误码
进程中,如果父进程没有等待子进程返回的信息,那么会出现僵尸进程,而我们的线程也是如此。
进程中有 wait(),waitpid() 函数进行等待
线程中有 pthread_join()
int pthread_join(pthread_t thread, void **value_ptr);
参数:thread(线程ID)
value_ptr:它指向一个指针,后者指向线程的返回值
返回值:成功返回0,失败返回错误码
调用该函数的线程将挂起等待,知道ID为thread的线程终止。我们知道线程的退出方式有几种,所以pthread_join() 得到的终止状态也是不同的。
1.如果thread线程通过return 返回,value_ptr 所指向的单元里存放的是thread线程函数的返回值
2.如果是线程被其他线程调用pthread_cancel() ,value_ptr所指向的单元里存放的是常数 PTHREAD_CANCELED
3.如果thread线程是自己调用pthread_exit() 终止的,value_ptr所指向的单元存放的是传给 pthread_exit的参数
4.如果对线程终止状态不感兴趣,value_ptr = NULL
线程等待实例:
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<string.h>
void *thread1(void *arg)
{
printf("thread 1 return ...\n");
int *p = (int *)malloc(sizeof(int));
*p = 1;
return (void *)p; //return 返回
}
void *thread2(void *arg)
{
printf("thread 2 exit ...\n");
int *p = (int *)malloc(sizeof(int));
*p = 2;
pthread_exit((void *)p); //pthread_exit 退出
}
void *thread3(void* arg)
{
while(1)
{
printf("thread 3 is running..\n");
sleep(1);
}
}
int main()
{
pthread_t tid;
void *ret;
//线程1
pthread_create(&tid,NULL,thread1,NULL);
pthread_join(tid,&ret);
printf("thread return , thread id %x,return code %d\n",tid,*(int *)ret);
free(ret);
//线程2
pthread_create(&tid,NULL,thread2,NULL);
pthread_join(tid,&ret);
printf("thread return,thread id %x,return code %d\n",tid,*(int*)ret);
free(ret);
//线程3
pthread_create(&tid,NULL,thread3,NULL);
sleep(5);
pthread_cancel(tid); //pthread_cancel 杀死3号线程
pthread_join(tid,&ret);
if(ret == PTHREAD_CANCELED)
{
printf("thread return,thread id %x,return code PTHREAD_CANCELED\n",tid);
}
else{
printf("thread return,thread id %x,return code NULL\n",tid);
}
return 0;
}
代码结果:
线程分离:
joinable: 可结合的
detach:可分离的
为什么需要线程分离?
1.默认情况下,新创建的线程是 joinable 的,线程退出后,需要对其进行 pthread_join 操作,否则无法释放资源,从而造成内存泄露。
2.如果我们不关心线程的返回值,调用 pthread_join() 是一种负担,这时,我们可以告诉系统,当线程退出时,自动的释放线程的资源。
函数有两个:
线程组内其他线程对目标线程进行分离:
int pthread_detach(pthread_t thread);
线程自己分离:
pthread_detach(pthread_self());
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<string.h>
void *thread(void *arg)
{
pthread_detach(pthread_self()); //自己分离
printf("thread running ...\n");
return NULL;
}
int main()
{
pthread_t tid;
if(pthread_create(&tid,NULL,thread,NULL) != 0)
{
printf("pthread_create failed\n");
return 1;
}
int ret = 0;
sleep(1);
if(pthread_join(tid,NULL) == 0) //等待,但是线程已经分离,资源被回收了,等待失败
{
printf("pthread wait success \n");
ret = 0;
}
else{
printf("pthread wait failed \n");
ret = 1;
}
return ret;
}
ps:
对比进程和线程的函数:
进程 线程
pid pthread
fork() pthread_create
wait() pthread_join
僵尸进程 僵线程
exit pthread_exit
kill //他杀 int pthread_cancel(tid) cancel,线程不会立即退出,而是要等到取消点才退出
取消点:凡是系统调用的地方都是取消点
人为设置一个取消点:void pthread_testcancel(void)