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

回收子线程

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 类型被修改为结构体实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383223.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统编程----15(线程与进程函数之间的对比,线程属性及其函数,线程属性控制流程,线程使用注意事项,线程库)

对比 进程 线程 fork pthread_create exit (10) pthread_exit &#xff08;void *&#xff09; wait (int *) pthread_join &#xff08;&#xff0c;void **&#xff09;阻塞 kill pthread_cancel ();必须到取消点&#xff08;检查点&#xff09;&#xff1a;…

Linux系统编程----16(线程同步,互斥量 mutex,互斥锁的相关函数,死锁,读写锁)

同步概念 所谓同步&#xff0c;即同时起步&#xff0c;协调一致。不同的对象&#xff0c;对“同步”的理解方式略有不同。如&#xff0c;设备同步&#xff0c;是指在两 个设备之间规定一个共同的时间参考&#xff1b;数据库同步&#xff0c;是指让两个或多个数据库内容保持一致…

Linux系统编程---17(条件变量及其函数,生产者消费者条件变量模型,生产者与消费者模型(线程安全队列),条件变量优点,信号量及其主要函数,信号量与条件变量的区别,)

条件变量 条件变量本身不是锁&#xff01;但它也可以造成线程阻塞。通常与互斥锁配合使用。给多线程提供一个会合的场所。 主要应用函数&#xff1a; pthread_cond_init 函数pthread_cond_destroy 函数pthread_cond_wait 函数pthread_cond_timedwait 函数pthread_cond_signa…

Linux系统编程---18(线程池相关概念及其实现)

线程池 概念&#xff1a; 一堆线程任务队列 作用 避免大量线程频繁的创建/销毁时间成本避免瞬间大量线程创建耗尽资源&#xff0c;程序崩溃危险 实现 创建固定数量的线程创建一个线程安全的任务队列 一种线程使用模式。 线程过多会带来调度开销&#xff0c;进而影响缓…

设计模式--1(设计模式基础,设计模式基本原则,设计模式分类)

设计模式基础 模式 在一定环境中解决某一问题的方案&#xff0c;包括三个基本元素–问题&#xff0c;解决方案和环境。大白话&#xff1a;在一定环境下&#xff0c;用固定套路解决问题。 设计模式 是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使…

设计模式----2(简单工厂模式的概念,简单工厂模式的实现,简单工厂模式的优缺点)

简单工厂模式 简单工厂模式的概念 简单工厂模式属于类的创建型模式,又叫做静态工厂方法模式。通过专门定义一个类来负 责创建其他类的实例&#xff0c;被创建的实例通常都具有共同的父类。 具体分类 工厂&#xff08;Creator&#xff09;角色 简单工厂模式的核心&#xff0…

设计模式---3(工厂方法模式的概念,工厂方法模式的实现,工厂方法模式和简单工厂模式比较)

工厂方法模式 概念 工厂方法模式同样属于类的创建型模式又被称为多态工厂模式 。 工厂方法模式的意义 定义一个创建产品对象的工厂接口&#xff0c;将实际创建工作推迟到子类当中。 核心工厂类不再负责产品的创建&#xff0c;这样核心类成为一个抽象工厂角色&#xff0c;仅…

设计模式---4(抽象工厂模式的概念,产品组和产品等级的概念,抽象工厂模式的实现)

抽象工厂模式 抽象工厂模式的概念 抽象工厂模式是所有形态的工厂模式中最为抽象和最其一般性的。抽象工厂模式可以向 客户端提供一个接口&#xff0c;使得客户端在不必指定产品的具体类型的情况下&#xff0c;能够创建多个产品 族的产品对象。 抽象工厂的角色及其职责 抽象工…

1.c++中初始化列表和构造函数初始化的区别是什么?2.类的成员变量的初始化顺序是按照声明顺序吗?

初始化列表和构造函数初始化的区别是什么&#xff1f; 初始化和赋值对内置类型的成员没有太大的区别&#xff0c;在成员初始化列表和构造函数体内进行&#xff0c;在性能和结果上都是一样的。只有一些需要注意的事项 初始化列表一般情况如下&#xff1a; Date(int year, int …

设计模式---5(建造者模式的概念及其实现,建造者模式的角色与职责,建造者模式和工厂模式的区别)

建造者模式 建造者模式的概念 Builder 模式也叫建造者模式或者生成器模式&#xff0c;是由 GoF 提出的 23 种设计模式中的一种。 Builder 模式是一种对象创建型模式之一&#xff0c;用来隐藏复合对象的创建过程&#xff0c;它把复合对象的 创建过程加以抽象&#xff0c;通过子…

system阻塞SIGCHLD信号原因

system阻塞SIGCHLD信号原因 标签&#xff1a; c 2014-11-08 11:58 198人阅读 评论(0) 收藏 举报 分类&#xff1a; linux编程&#xff08;1&#xff09; 代码1&#xff1a;APUE10.18节的system函数源代码 int system(const char *cmdstring) /* with appropriate signal ha…

设计模式6---(单例模式的概念及其实现(懒汉式和饿汉式),线程安全)

单例模式 单例模式的概念 单例模式是一种对象创建型模式&#xff0c;使用单例模式&#xff0c;可以保证为一个类只生成唯一的实例对象。也就是说&#xff0c;在整个程序空间中&#xff0c;该类只存在一个实例对象。 GoF 对单例模式的定义是&#xff1a;保证一个类、只有一个实…

套接字编程---2(TCP套接字编程的流程,TCP套接字编程中的接口函数,TCP套接字的实现,TCP套接字出现的问题,TCP套接字多进程版本,TCP套接字多线程版本)

TCP模型创建流程图 TCP套接字编程中的接口 socket 函数 #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int socket(int domain, int type, int protocol); domain: AF_INET 这是大多数用来产生socket的协议&#xff0c;使用TCP或UDP来传输&…

Linux中netstat工具详解

简介 Netstat 命令用于显示各种网络相关信息&#xff0c;如网络连接&#xff0c;路由表&#xff0c;接口状态 (Interface Statistics)&#xff0c;masquerade 连接&#xff0c;多播成员 (Multicast Memberships) 等等。 常见参数 -a (all)显示所有选项&#xff0c;默认不显示…

网络基础 2-1(应用层,HTTP三点注意,HTTP协议格式, 最简单的HTTP服务器)

应用层 应用层 负责应用程序之间的数据沟通-----协议都是用户自己定的 自定制协议&#xff1a; 结构化数据传输 序列化&#xff1a; 将数据对象以指定的协议&#xff08;数据格式&#xff09;进行可用于持久化存储或者数据传输时的数据组织 例如在分布式的系统中&#xf…

网络基础2-2(传输层,端口,详谈UDP)

传输层 负责数据能够从发送端传输接收端. 端口号 端口号(Port)标识了一个主机上进行通信的不同的应用程序;在TCP/IP协议中, 用 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信(可以通过 netstat -n查看);一个端口只能被一个…

网络基础2-3(TCP协议,三次握手,四次挥手,TIME_WAIT状态的作用,TCP如何保证可靠传输,TCP连接中状态转化,滑动窗口,流量控制,快速重传,拥塞窗口,延迟应答,捎带应答,粘包问题)

TCP协议 TCP协议概念 TCP全称为 “传输控制协议(Transmission Control Protocol”). 人如其名, 要对数据的传输进行一个详细的控制 TCP协议格式 1. 源/目的端口号: 表示数据是从哪个进程来, 到哪个进程去; 2. 32位序号/32位确认号: 后面详细讲; 3. 4位TCP报头长度: 表示该…

字符串题目 1 --------判断两个字符串是否为旋转词

题目描述 如果一个字符串为str&#xff0c;把字符串的前面任意部分挪到后面形成的字符串交str的旋转词。比如str“12345”&#xff0c;str的旋转串有“12345”、“45123”等等。给定两个字符串&#xff0c;判断是否为旋转词。 输入描述: 输出包含三行&#xff0c;第一个两个…

字符串题目---2判断两个字符串是否为变形词

题目描述 给定两个字符串str1和str2&#xff0c;如果str1和str2中出现的字符种类出现的一样且每种字符出现的次数也一样&#xff0c;那么str1和str2互为变形词。请判断str1和str2是否为变形词 输入描述: 输入包括3行&#xff0c;第一行包含两个整数n&#xff0c;m(1 \leq n,…

设计模式7----代理模式

代理模式 概念 Proxy 模式又叫做代理模式&#xff0c;是结构型的设计模式之一&#xff0c;它可以为其他对象提供一 种代理&#xff08;Proxy&#xff09;以控制对这个对象的访问。 所谓代理&#xff0c;是指具有与代理元&#xff08;被代理的对象&#xff09;具有相同的接口的…