Linux:回收循环创建的多个线程
上午我说了循环创建多个线程,由于进程与线程是如此的相似,进程我们知道要回收,那么线程也自然要回收啦。我们接着看控制原语:
线程与共享
线程间共享全局变量!
【牢记】:线程默认共享数据段、代码段等地址空间,常用的是全局变量。而进程不共享全局变量,只能借助mmap。
pthread_exit函数
将单个线程退出
void pthread_exit(void *retval); 参数:retval表示线程退出状态,通常传NULL
思考:使用exit将指定线程退出,可以吗? 【pthrd_exit.c】
结论:线程中,禁止使用exit函数,会导致进程内所有线程全部退出。
在不添加sleep控制输出顺序的情况下。pthread_create在循环中,几乎瞬间创建5个线程,但只有第1个线程有机会输出(或者第2个也有,也可能没有,取决于内核调度)如果第3个线程执行了exit,将整个进程退出了,所以全部线程退出了。
所以,多线程环境中,应尽量少用,或者不使用exit函数,取而代之使用pthread_exit函数,将单个线程退出。任何线程里exit导致进程退出,其他线程未工作结束,主控线程退出时不能return或exit。
另注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。
总结exit、return、pthread_exit各自退出效果。
return:返回到调用者那里去。
pthread_exit():将调用该函数的线程退出
exit: 将进程退出。
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 **
参数 retval 非空用法。
调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:
- 如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值。
- 如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存放的是常数PTHREAD_CANCELED。
- 如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数。
- 如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数。
上面说的很清楚啦,所以回收线程的代码实现也很简单啦:
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
int x;
int y;
char p[128];
}my_func;
void *func(void*arg)
{
my_func *mf = (my_func*)malloc(sizeof(my_func));
int i = (int)arg;
mf->x = i;
mf->y = i * i;
strcpy(mf->p, "my lover is dandan.");
printf("我是第%d个线程,我的线程ID是%lu\n", i + 1, pthread_self());
pthread_exit(mf);
}
int main(void)
{
pthread_t pth[5];
my_func *mf;//这里是指针啊,是指针啊,不是一个实例啊
for (int i = 0; i != 5; i++)
{
pthread_create((pth + i), NULL, func, (void*)i);
if (!pthread_join(pth[i], (void**)&mf))
{
printf("回收线程成功!线程ID:%lu。\n", pth[i]);
printf("my_func中的x = %d, y = %d, p = %s。\n\n", mf->x, mf->y, mf->p);
}
else
printf("失败!\n");
}
return 0;
}
主要是各种转化要注意,还有的是:my_func *mf;//这里是指针啊,是指针啊,不是一个实例啊 这句话很重要啊,我就说为什么我的mf输出像是没有经过初始化和赋值操作的。还有,不用担心我没有free而造成内存泄漏,pthread_exit函数是把这些考虑好了的。还有我的pthread_exit是传参数进去的,主要是想获取一下线程退出的状态。是不是和wait很类似?
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?