回收子线程

pthread_join 函数

阻塞等待线程退出,获取线程退出状态 其作用,对应进程中 waitpid() 函数。

int  pthread_join    (pthread_t      thread,void**   retval);

成功:0,失败:错误号
参数:thread:线程ID(注意 :不是指针);retval:存储线程结束状态
对比记忆:

  1. 进程中:main 返回值、exit 参数–>int;等待子进程结束 wait 函数参数–>int*
  2. 线程中:线程主函数返回值、pthread_exit-->void*;等待线程结束 pthread_join 函数参数–>void**
  3. 对于进程而言,wait函数的返回值是int,所以获取退出值使用int*
  4. 对于线程,void*作为函数返回值,回收使用void**
示例1
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>typedef struct{int a;int b;
}exit_t;void * tfn(void *arg)   //子线程函数
{//子线程函数中定义 ret;exit_t *ret; //用结构体定义一个变量ret=malloc(sizeof(exit_t));ret->a = 100;ret->b = 300;//返回ret 这个值,线程退出pthread_exit((void *)ret);
}int main(void)
{pthread_t tid;exit_t *retval;pthread_create(&tid,NULL,tfn,NULL);/*调用pthread_join可以获取线程退出状态*///第一个回收线程ID,第二个回收退出的值                                   pthread_join(tid,(void **)&retval);   //wait(&status);printf("a = %d,b = %d\n",retval->a,retval->b);return 0;
}

注意事项

调用该函数的线程将挂起等待,直到 id 为 thread 的线程终止。 thread 线程以不同的方法终止,通过 pthread_join 得到的终止状态是不同的,总结如下:

  1. 如果 thread 线程通过 return 返回,retval 所指向的单元里存放的是 thread 线程函数的返回值。
  2. 如果 thread 线程被别的线程调用 pthread_cancel 异常终止掉,retval 所指向的单元里存放的是常数PTHREAD_CANCELED。
  3. 如果 thread 线程是自己调用 pthread_exit 终止的,retval 所指向的单元存放的是传给 pthread_exit 的参数。
  4. 如果对 thread 线程的终止状态不感兴趣,可以传 NULL 给 retval 参数。

示例2

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<string.h>typedef struct {char ch;int var;char str[64];
}exit_t;void *thrd_func(void *arg)
{//创建结构体变量exit_t * retvar = (exit_t *)malloc(sizeof(exit_t));//赋值retvar->ch='m';retvar->var = 200;strcpy(retvar->str,"我的返回值");//子线程退出pthread_exit((void *)retvar);}int main(void)
{pthread_t tid;int ret;exit_t * retval;//主控线程IDprintf(" In main1 id = %lu,pid = %u\n",pthread_self(),getpid());ret = pthread_create(&tid,NULL,thrd_func,NULL);if(ret != 0){fprintf(stderr,"pthread_create error:%s\n",strerror(ret));exit(1);}pthread_join(tid,(void **)&retval);printf("子线程返回值为\n");printf("ch = %c ,var = %d,str = %s\n",retval->ch,retval->var,retval->str);pthread_exit((void *)1);return 0;
}

使用 pthread_join 函数将循环创建的多个子线程回收。
/*回收多个子线程*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>int var=100;void *tfn(void *arg)  //每个子线程进行回收
{int i;i = (int)arg;sleep(i);  //输出有顺序if(i == 1){var = 333;printf("var = %d\n",var);return (void *)var;}else if(i == 3){var = 777;printf("I'm %d th 线程,线程ID为 %lu var = %d\n",i+1,pthread_self(),var);pthread_exit((void *)var);}else {printf("I'm %d th 线程,线程ID = %lu\n var = %d\n",i+1,pthread_self(),var);pthread_exit((void *)var);}return NULL;
}int main(void)
{pthread_t tid[5];int i;int *ret[5]; //保存 5个线程的退出值for(i = 0;i < 5; i++)//循环创建多个子线程pthread_create(&tid[i],NULL,tfn,(void*)i);for(i=0;i < 5; i++){ //对多个子线程进行回收pthread_join(tid[i],(void **)&ret[i]);printf("-----------%d th ret = %d\n",i,(int)ret[i]);}printf("I'm main 线程 tid = %lu\t var = %d\n",pthread_self(),var);//主控线程也打印777,原因是共享全局变量sleep(i);return 0;
}

线程分离

pthread_detach 函数

进程当中没有
实现线程分离
int pthread_detach(pthread_t thread); 成功:0;失败:错误号

  1. 线程分离状态:指定该状态,线程主动与主控线程断开关系。线程结束后,其退出状态不由其他线程获取,而 直接自己自动释放。网络、多线程服务器常用。
  2. 进程若有该机制,将不会产生僵尸进程。僵尸进程的产生主要由于进程死后,大部分资源被释放,一点残留资 源仍存于系统中,导致内核认为该进程仍存在。
    也可使用 pthread_create 函数参 2(线程属性)来设置线程分离。
使用 pthread_detach 函数实现线程分离
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>void *tfn(void *arg)
{int n=3;while(n--){printf("thread count %d\n",n);sleep(1);}   return (void *)1;
}int main(void)
{pthread_t tid;void *tret;int err;pthread_create(&tid,NULL,tfn,NULL);pthread_detach(tid);        //让线程分离   ----自动退出,无系统残留资源while(1){err = pthread_join(tid,&tret);printf("---------err= %d\n",err);if(err != 0)fprintf(stderr,"thread error: %s\n",strerror(err));              elsefprintf(stderr,"thread exit code %d\n",(int)tret);sleep(1);}       return 0;
}

注意事项

一般情况下,线程终止后,其终止状态一直保留到其它线程调用 pthread_join 获取它的状态为止。但是线程也 可以被置为 detach 状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。**不能对一个已 经处于 detach 状态的线程调用 pthread_join,这样的调用将返回 EINVAL 错误。**也就是说,如果已经对一个线程调用 了 pthread_detach 就不能再调用 pthread_join 了。

杀死线程

pthread_cancel 函数

杀死(取消)线程 其作用,对应进程中 kill() 函数。
int pthread_cancel(pthread_t thread); 成功:0;失败:错误号
注意线程的取消并不是实时的,而有一定的延时。需要等待线程到达某个取消点(检查点)。

  1. 类似于玩游戏存档,必须到达指定的场所(存档点,如:客栈、仓库、城里等)才能存储进度。杀死线程也不是 立刻就能完成,必须要到达取消点。
  2. 取消点:是线程检查是否被取消,并按请求进行动作的一个位置。通常是一些系统调用 creat,open,pause, close,read,write..... 执行命令 man 7 pthreads 可以查看具备这些取消点的系统调用列表。也可参阅 APUE.12.7 取消选项小节。
    可粗略认为一个系统调用(进入内核)即为一个取消点。如线程中没有取消点,可以通过调用 pthreestcancel 函数 自行设置一个取消点。
  3. 被取消的线程, 退出值定义在Linux的pthread库中。常数PTHREAD_CANCELED的值是**-1**。可在头文件pthread.h 中找到它的定义:#define PTHREAD_CANCELED((void*)-1)。因此当我们对一个已经被取消的线程使用 pthread_join 回收时,得到的返回值为-1。
终止线程的三种方法
/*三种退出线程的方法*/                                                       #include<stdio.h>
#include<string.h>
#include<pthread.h>void *tfn1(void *arg)  //第一个线程
{printf("thread 1 returning\n");return (void *)111;
}void *tfn2(void *arg)   //第二个线程
{printf("thread 2 exiting\n");pthread_exit((void *)222);
}void *tfn3(void *arg)   //第三个线程
{while(1){printf("thread 3:I'm going to die in 3 seconds ....\n");sleep(1);//pthread_testcancel();//自己添加取消点}return (void *)666;
}int main(void)
{pthread_t tid;void *tret = NULL;pthread_create(&tid,NULL,tfn1,NULL);pthread_join(tid,&tret);printf("thread 1 exit code = %d\n\n",(int)tret);pthread_create(&tid,NULL,tfn2,NULL);pthread_join(tid,&tret);printf("thread 2 exit code = %d\n\n",(int)tret);pthread_create(&tid,NULL,tfn3,NULL);sleep(3);pthread_cancel(tid);pthread_join(tid,&tret);printf("thread 3 exit code = %d\n\n",(int)tret);return 0;
}


当把一个线程杀死后,它的返回值是-1;

终止线程方式

总结:终止某个线程而不终止整个进程,
有三种方法:

  1. 从线程主函数 return。这种方法对主控线程不适用,从 main 函数 return 相当于调用 exit。
  2. 一个线程可以调用 pthread_cancel 终止同一进程中的另一个线程。
  3. 线程可以调用 pthread_exit 终止自己。

pthread_equal 函数

比较两个线程 ID 是否相等。
int pthread_equal (pthread_t t1,pthread_t t2); 有可能 Linux 在未来线程 ID pthread_t 类型被修改为结构体实现。

Linux系统编程---14(回收子线程,回收多个子线程,线程分离,杀死线程)相关推荐

  1. 【Linux系统编程】进程退出和回收进程资源

    00. 目录 文章目录 00. 目录 01. 进程退出函数 02. 进程退出讨论 03. 回收进程资源 04. 附录 01. 进程退出函数 #include <stdlib.h>void ...

  2. Linux系统编程14:进程入门之Linux进程中非常重要的概念之进程地址空间-原来我们看到的地址全部是虚拟的

    文章目录 (1)旧知回顾 (2)程序地址空间? A:同一个地址有两个数据? B:物理地址和虚拟地址 C:进程地址空间及作用 D:进程地址空间如何工作 (1)旧知回顾 学习C/C++总免不了这张图 这张 ...

  3. 【Linux】一步一步学Linux系统编程教程汇总(暂时暂停更新......)

    00. 目录 文章目录 00. 目录 01. 概述和标准 02. 文件操作 03. 进程概念 04. 进程间通信 05. 多线程 06. 信号 07. 同步与互斥 08. 高级IO 09. 其它 10 ...

  4. 【README】Linux系统编程必读:本专栏内容提要以及系统调用接口总结

    文章目录 前言 第一部分:博客知识点 (1)基础篇 Linux系统编程1:Linux中使用率最高的一些命令 Linux系统编程2:详解Linux中的权限问题 Linux系统编程3:基础篇之详解Linu ...

  5. 【Linux系统编程】守护进程、线程

    ------------->[Linux系统编程/网络编程](学习目录汇总) <-------------- 目录 1.守护进程 1.1 进程组 1.2 会话 1.3 setsid()函数 ...

  6. 【Linux | 系统编程】Linux系统编程(文件、进程线程、进程间通信)

    文章目录 Linux系统编程 文件IO open/close函数 read/write函数 文件描述符 阻塞.非阻塞 fcntl函数 lseek函数 传入传出参数 文件系统 文件存储 文件操作 sta ...

  7. Linux系统编程【文件IO、进程、进程间通信、信号、线程、互斥】

    linux系统编程 个人通过学习,手打了一份48000字的Linux系统编程的笔记,包含了[文件IO.进程.进程间通信.信号.多线程.互斥]等知识点,并给出了大量的代码案例对每个重要的知识点进行了代码 ...

  8. Linux系统编程——线程私有数据

    在多线程程序中.常常要用全局变量来实现多个函数间的数据共享.因为数据空间是共享的,因此全局变量也为全部线程共同拥有. 測试代码例如以下: #include <stdio.h> #inclu ...

  9. linux线程并不真正并行,Linux系统编程学习札记(十二)线程1

    Linux系统编程学习笔记(十二)线程1 线程1: 线程和进程类似,但是线程之间能够共享更多的信息.一个进程中的所有线程可以共享进程文件描述符和内存. 有了多线程控制,我们可以把我们的程序设计成为在一 ...

最新文章

  1. crontab用法 时间配置_Linux指定的时间运行自定义命令的两种方式
  2. rgb cmyk lab的区别
  3. SAP ABAP XSLT extract custom style
  4. spriteatlas 白屏的问题_Discuz白屏问题解决思
  5. 特斯拉最廉价车型——基础版Model 3将取消网售
  6. IBM主机增加“交易实时分析”新能力
  7. 433.最小基因变化
  8. Tableau数据连接与加载(数据提取)
  9. 做了一款股票复盘工具
  10. 国美在线php面试题,国美销售专员的面试考题
  11. 计算几何:记录求两球体相交部分体积(球缺)模板
  12. 怎么起用计算机无线开关,笔记本无线网络开关,详细教您如何打开笔记本电脑无线网卡开关...
  13. Wondows Sever 2003密钥【收集】
  14. python语言工具_可爱的 Python
  15. GitHub 上 100K+ Star 的前端面试开源项目汇总(进大厂必备)
  16. 属兔2013年蛇年运程
  17. opencv-python 去除图片文字
  18. 算法系统下的外卖平台:饿了么可选多等5分钟,美团无差别8分钟
  19. u盘装机维护系统工具图文解说
  20. 空中乘务类毕业论文文献都有哪些?

热门文章

  1. [EffectiveC++]item34:区分接口继承和实现继承
  2. Akka应用模式:分布式应用程序设计实践指南pdf
  3. Delta DVP 系列 PLC 各装置 Modbus 地址
  4. nios pio interrupt 的使能
  5. 可能用得上的jquery 插件
  6. 【摘录】C语言中利用 strtok函数进行字符串分割
  7. Windows MobileCE 开发书籍大全
  8. 区别和联系_动机与主题的区别与联系
  9. mybatis源码_Mybatis源码之SqlSession
  10. java 一维数组_java基础 ---- 一维数组