【并发程序设计】7.线程回收

7.线程回收

两种方法回收线程

  1. 使用pthread_join 函数
  2. 使线程分离

1.pthread_join 函数

  1. 原型

    #include <pthread.h>
    int pthread_join(pthread_t thread, void **retval);
    
  2. 功能:等待一个线程的结束

  3. 参数

    • thread:需要等待的线程ID。
    • retval:指向一个指针,用于存储被等待线程的返回值。如果不关心返回值,可以设置为NULL。
  4. 返回值

    • 成功时,返回0;
    • 失败时,返回一个非零的错误码。
  5. 注意pthread_join 是阻塞函数,如果回收的线程没有结束,则一直等待

  6. 示例

    创建了一个子线程,并在子线程中执行一个函数fun。主线程等待子线程结束后,打印子线程的返回值。

    #include <stdio.h>
    #include <pthread.h>
    #include <unistd.h>
    void *fun(void * arg)
    {
    	int i;
    	pthread_detach(pthread_self());
    	for(i=0; i<3; i++)
    	{
    		printf("child %d\n",i);
    		sleep(1);
    	}
    	pthread_exit("fun return");
    }
    int main(int argc, const char *argv[])
    {
    	int i = 0;
    	void *retf;
    	pthread_t tid;
    	pthread_create(&tid,NULL,fun,(void *)i);
    	pthread_join(tid,&retf);//等待线程结束
    	printf("%s\n",(char*)retf);
    	return 0;
    }
    

2.线程分离

线程分离是将线程设置为不被其他线程等待或回收的状态,从而在退出时自动释放资源。

  • 如果不需要关心线程的返回值,或者不希望等待线程结束,可以将线程设置为分离状态。这样,线程在结束时会自动释放其所占用的资源,无需进行pthread_join操作,从而减少了程序的负担。
  • 注意:一旦线程被分离,就不能再被其他线程回收,也就不能调用pthread_join。因此,在决定分离线程之前,应该仔细考虑线程的用途和生命周期。

两种方式使线程分离

  1. 使用pthread_detach函数
  2. 使用pthread_attr_init函数和pthread_attr_setdetachstate函数,设置线程属性为分离
pthread_detach 函数
  1. 原型

    #include <pthread.h>
    int pthread_detach(pthread_t thread);
    
  2. 功能:将一个线程设置为分离状态,线程结束后(不会产生僵尸线程)

  3. 参数thread:需要设置为分离状态的线程ID。

  4. 返回值

    • 成功时,返回0;
    • 失败时,返回一个非零的错误码
  5. 示例

    #include <stdio.h>
    #include <pthread.h>
    #include <unistd.h>
    void *fun(void * arg)
    {
    	pthread_detach(pthread_self());//分离线程
    	printf("child %d\n",(int)arg);
    	pthread_exit(NULL);
    }
    int main(int argc, const char *argv[])
    {
    	int i;
    	pthread_t tid[10];
    	for(i=0; i<10; i++)//创建十个线程
    	{
    		pthread_create(&tid[i],NULL,fun,(void *)i);
    	}
    	sleep(10);//等待线程运行
    	return 0;
    }
    
设置线程属性为分离
pthread_attr_init函数
  1. 原型

    int pthread_attr_init(pthread_attr_t *attr);
    
  2. 功能:初始化一个线程属性对象

  3. 参数attr:指向要初始化的线程属性对象的指针。

  4. 返回值

    • 成功时,返回0;
    • 失败时,返回一个非零的错误码。
pthread_attr_setdetachstate函数
  1. 原型

    #include <pthread.h>
    int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
    
  2. 功能:设置线程属性对象的分离状态

  3. 参数

    • attr:指向要设置分离状态的线程属性对象的指针。

    • detachstate:指定线程的分离状态,可以是PTHREAD_CREATE_JOINABLE或PTHREAD_CREATE_DETACHED。

  4. 返回值

    • 成功时,返回0;
    • 失败时,返回一个非零的错误码。

示例:该线程在创建时就是分离的线程

pthread_attr_t attr;//定义线程属性变量
pthread_attr_init(&attr);//初始化该变量
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//设置属性为分离
pthread_create(&tid,&attr,fun,NULL);//创建线程

可以通过top命令查看进程占用的内存空间大小,检验线程是否被回收

注意:分离后,进程结束,线程也会随之结束。


取消线程

pthread_cancel 函数

  1. 原型

    #include <pthread.h>
    int pthread_cancel(pthread_t thread);
    
  2. 功能:取消一个线程的执行

  3. 参数thread:要取消执行的线程ID。

  4. 返回值

    • 成功时,返回0;
    • 失败时,返回一个非零的错误码。
  5. 注意:线程的取消要有取消点才可以,不是说取消就取消,线程的取消点主要是阻塞的系统调用如sleep();

    若没有取消点,可手动设置一个取消点

pthread_testcancel 函数

  1. 原型

    #include <pthread.h>
    void pthread_testcancel(void);
    
  2. 功能:在当前线程中创建一个取消点,这样如果该线程收到取消请求时,它可以在这个点上响应并执行相应的取消操作。

pthread_setcancelstate函数

  1. 原型

    #include <pthread.h>
    int pthread_setcancelstate(int state, int *oldstate);
    
  2. 功能:设置线程的取消状态

  3. 参数

    • state:指定线程的取消状态,可以是PTHREAD_CANCEL_ENABLE或PTHREAD_CANCEL_DISABLE。

    • oldstate:指向一个整型变量的指针,用于保存线程原来的取消状态。

  4. 返回值

    • 成功时,返回0;
    • 失败时,返回一个非零的错误码。

pthread_setcanceltype函数

  1. 原型

    #include <pthread.h>
    int pthread_setcanceltype(int type, int *oldtype);
    
  2. 功能:设置线程的取消类型

  3. 参数

    • type:指定线程的取消类型,可以是PTHREAD_CANCEL_DEFERRED(等到取消点才取消)、PTHREAD_CANCEL_ASYNCHRONOUS(目标线程会立即取消)

    • oldtype:指向一个整型变量的指针,用于保存线程原来的取消类型。

  4. 返回值

    • 成功时,返回0;
    • 失败时,返回一个非零的错误码。

示例:线程设置为可取消后,被取消,线程结束

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void *fun(void * arg)
{
	int i;
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);//设置线程为不能取消
	for(i=0; i<10; i++)
	{
		printf("child %d\n",i);
		sleep(1);
	}
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//设置线程为可以取消
	for(i=10; i<20; i++)
	{
		printf("child %d\n",i);
		sleep(1);
	}
	pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
	int i = 0;
	pthread_t tid;
	pthread_create(&tid,NULL,fun,(void *)i);
	sleep(5);//等待五秒	
	pthread_cancel(tid);//取消线程

	while(1)
	{
		sleep(1);
	}
	return 0;
}

线程的清理

当线程非正常终止,需要清理一些资源。

pthread_cleanup_push函数

  1. 原型

    #include <pthread.h>
    void pthread_cleanup_push(void (*routine)(void *), void *arg);
    
  2. 功能:将一个清理函数压入线程的清理栈中

  3. 参数

    • routine:指向要压入清理栈中的清理函数的指针。

      • 被pthread_cancel取消掉。

      • 执行pthread_exit

      • 非0参数执行pthread_cleanup_pop()

    • arg:传递给清理函数的参数。

pthread_cleanup_pop函数

  1. 原型

    #include <pthread.h>
    void pthread_cleanup_pop(int execute);
    
  2. 功能:用来解除之前通过pthread_cleanup_push注册的线程清理函数

  3. 参数execute:一个整数,表示是否执行清理函数。如果为非零值,则执行清理函数;如果为零,则不执行。

注意

  1. 必须成对使用,即使pthread_cleanup_pop不会被执行到也必须写上,否则编译错误。

  2. pthread_cleanup_pop()被执行且参数为0,pthread_cleanup_push回调函数routine不会被执行.

  3. pthread_cleanup_push 和pthread_cleanup_pop可以写多对,routine执行顺序正好相反

  4. 线程内的 return 可以结束线程,也可以给pthread_join返回值,但不能触发pthread_cleanup_push里面的回调函数,所以我们结束线程尽量使用pthread_exit退出线程。

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值