Linux系统编程---14(回收子线程,回收多个子线程,线程分离,杀死线程)
回收子线程
pthread_join 函数
阻塞等待线程退出,获取线程退出状态 其作用,对应进程中 waitpid()
函数。
int pthread_join (pthread_t thread,void** retval);
成功:0,失败:错误号
参数:thread:线程ID(注意 :不是指针);retval:存储线程结束状态
对比记忆:
- 进程中:main 返回值、exit 参数–>int;等待子进程结束 wait 函数参数–>
int*
- 线程中:线程主函数返回值、
pthread_exit-->void*
;等待线程结束 pthread_join 函数参数–>void**
- 对于进程而言,wait函数的返回值是int,所以获取退出值使用
int*
- 对于线程,
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 得到的终止状态是不同的,总结如下:
- 如果 thread 线程通过 return 返回,retval 所指向的单元里存放的是 thread 线程函数的返回值。
- 如果 thread 线程被别的线程调用 pthread_cancel 异常终止掉,retval 所指向的单元里存放的是常数PTHREAD_CANCELED。
- 如果 thread 线程是自己调用 pthread_exit 终止的,retval 所指向的单元存放的是传给 pthread_exit 的参数。
- 如果对 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;失败:错误号
- 线程分离状态:指定该状态,线程主动与主控线程断开关系。线程结束后,其退出状态不由其他线程获取,而 直接自己自动释放。网络、多线程服务器常用。
- 进程若有该机制,将不会产生僵尸进程。僵尸进程的产生主要由于进程死后,大部分资源被释放,一点残留资 源仍存于系统中,导致内核认为该进程仍存在。
也可使用 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;失败:错误号
注意:线程的取消并不是实时的,而有一定的延时。需要等待线程到达某个取消点(检查点)。
- 类似于玩游戏存档,必须到达指定的场所(存档点,如:客栈、仓库、城里等)才能存储进度。杀死线程也不是 立刻就能完成,必须要到达取消点。
- 取消点:是线程检查是否被取消,并按请求进行动作的一个位置。通常是一些系统调用
creat,open,pause, close,read,write.....
执行命令man 7 pthreads
可以查看具备这些取消点的系统调用列表。也可参阅APUE.12.7
取消选项小节。
可粗略认为一个系统调用(进入内核)即为一个取消点。如线程中没有取消点,可以通过调用 pthreestcancel 函数 自行设置一个取消点。 - 被取消的线程, 退出值定义在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;
终止线程方式
总结:终止某个线程而不终止整个进程,
有三种方法:
- 从线程主函数 return。这种方法对主控线程不适用,从 main 函数 return 相当于调用 exit。
- 一个线程可以调用 pthread_cancel 终止同一进程中的另一个线程。
- 线程可以调用 pthread_exit 终止自己。
pthread_equal 函数
比较两个线程 ID 是否相等。
int pthread_equal (pthread_t t1,pthread_t t2);
有可能 Linux 在未来线程 ID pthread_t
类型被修改为结构体实现。
Linux系统编程---14(回收子线程,回收多个子线程,线程分离,杀死线程)相关推荐
- 【Linux系统编程】进程退出和回收进程资源
00. 目录 文章目录 00. 目录 01. 进程退出函数 02. 进程退出讨论 03. 回收进程资源 04. 附录 01. 进程退出函数 #include <stdlib.h>void ...
- Linux系统编程14:进程入门之Linux进程中非常重要的概念之进程地址空间-原来我们看到的地址全部是虚拟的
文章目录 (1)旧知回顾 (2)程序地址空间? A:同一个地址有两个数据? B:物理地址和虚拟地址 C:进程地址空间及作用 D:进程地址空间如何工作 (1)旧知回顾 学习C/C++总免不了这张图 这张 ...
- 【Linux】一步一步学Linux系统编程教程汇总(暂时暂停更新......)
00. 目录 文章目录 00. 目录 01. 概述和标准 02. 文件操作 03. 进程概念 04. 进程间通信 05. 多线程 06. 信号 07. 同步与互斥 08. 高级IO 09. 其它 10 ...
- 【README】Linux系统编程必读:本专栏内容提要以及系统调用接口总结
文章目录 前言 第一部分:博客知识点 (1)基础篇 Linux系统编程1:Linux中使用率最高的一些命令 Linux系统编程2:详解Linux中的权限问题 Linux系统编程3:基础篇之详解Linu ...
- 【Linux系统编程】守护进程、线程
------------->[Linux系统编程/网络编程](学习目录汇总) <-------------- 目录 1.守护进程 1.1 进程组 1.2 会话 1.3 setsid()函数 ...
- 【Linux | 系统编程】Linux系统编程(文件、进程线程、进程间通信)
文章目录 Linux系统编程 文件IO open/close函数 read/write函数 文件描述符 阻塞.非阻塞 fcntl函数 lseek函数 传入传出参数 文件系统 文件存储 文件操作 sta ...
- Linux系统编程【文件IO、进程、进程间通信、信号、线程、互斥】
linux系统编程 个人通过学习,手打了一份48000字的Linux系统编程的笔记,包含了[文件IO.进程.进程间通信.信号.多线程.互斥]等知识点,并给出了大量的代码案例对每个重要的知识点进行了代码 ...
- Linux系统编程——线程私有数据
在多线程程序中.常常要用全局变量来实现多个函数间的数据共享.因为数据空间是共享的,因此全局变量也为全部线程共同拥有. 測试代码例如以下: #include <stdio.h> #inclu ...
- linux线程并不真正并行,Linux系统编程学习札记(十二)线程1
Linux系统编程学习笔记(十二)线程1 线程1: 线程和进程类似,但是线程之间能够共享更多的信息.一个进程中的所有线程可以共享进程文件描述符和内存. 有了多线程控制,我们可以把我们的程序设计成为在一 ...
最新文章
- crontab用法 时间配置_Linux指定的时间运行自定义命令的两种方式
- rgb cmyk lab的区别
- SAP ABAP XSLT extract custom style
- spriteatlas 白屏的问题_Discuz白屏问题解决思
- 特斯拉最廉价车型——基础版Model 3将取消网售
- IBM主机增加“交易实时分析”新能力
- 433.最小基因变化
- Tableau数据连接与加载(数据提取)
- 做了一款股票复盘工具
- 国美在线php面试题,国美销售专员的面试考题
- 计算几何:记录求两球体相交部分体积(球缺)模板
- 怎么起用计算机无线开关,笔记本无线网络开关,详细教您如何打开笔记本电脑无线网卡开关...
- Wondows Sever 2003密钥【收集】
- python语言工具_可爱的 Python
- GitHub 上 100K+ Star 的前端面试开源项目汇总(进大厂必备)
- 属兔2013年蛇年运程
- opencv-python 去除图片文字
- 算法系统下的外卖平台:饿了么可选多等5分钟,美团无差别8分钟
- u盘装机维护系统工具图文解说
- 空中乘务类毕业论文文献都有哪些?