一、线程退出的 3 种方式
| 方式 | 触发者 | 本质 | 资源回收 |
|---|---|---|---|
| 线程执行完函数返回 | 线程自己 | 隐式退出,返回值就是 return 的值 | 必须 join 或 detach |
pthread_exit() | 线程自己 | 主动退出,可指定返回值 | 必须 join 或 detach |
pthread_cancel() | 其他线程 | 请求取消(异步/延迟) | 必须 join 或 detach |
⚠️ 无论哪种方式,线程结束后其资源(栈、TLS、内核结构)不会自动完全释放,除非被
join或detach。
| 场景 | 推荐做法 |
|---|---|
| 需要线程结果 | pthread_join() |
| 不需要结果, fire-and-forget | pthread_detach()(创建后立即 detach) |
| 需要中途终止线程 | pthread_cancel() + pthread_join(),但尽量用条件变量/标志位优雅退出 |
| 避免僵尸线程 | 确保每个线程都被 join 或 detach |
1. pthread_exit(void *retval)
关键点:
- 只能由线程自己调用(你笔记里写了,这是对的)
retval不能指向线程栈上的局部变量(线程退出后栈销毁,指针悬空)- 主线程调用
pthread_exit()不会导致进程退出,只会导致主线程退出,其他线程继续运行
void *my_thread(void *arg)
{
printf("线程执行---\n");
int *result = malloc(sizeof(int));
*result = 42;
pthread_exit(result); // 主动退出,返回 42
// 或者直接用 return result; 效果一样
}
int main(void)
{
pthread_t pthread;
pthread_create(&pthread, NULL, my_thread, NULL);
while (1)
{
/* code */
sleep(1);
printf("主线程---\n");
}
return 0;
}
2.pthread_join(pthread_t thread, void **retval)
作用:
- 阻塞等待指定线程结束
- 回收线程资源(栈、内核结构)
- 获取线程返回值(通过
retval输出参数)
⚠️ 坑:
- 一个线程只能被
join一次 - 如果线程已经被
detach,再join会返回EINVAL - 不
join也不detach→ 线程变成"僵尸线程",资源泄漏
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
void *my_thread(void *arg)
{
sleep(3);
printf("线程停止---\n");
}
int main(void)
{
pthread_t pthread;
pthread_create(&pthread,NULL,my_thread,NULL);
void *result;
pthread_join(pthread,result);
printf("主线程\n");
return 0;
}
3. pthread_detach(pthread_t thread)
作用:
- 告诉系统:我不关心这个线程的返回值,它结束后自动回收资源
detach后线程变成"分离状态",结束后立即释放资源,不可join
适用场景:
- 不需要知道线程结果(如后台守护线程、日志写入线程)
- 避免忘记
join导致资源泄漏
⚠️ 坑:
detach后不能再join- 如果线程返回了堆内存指针,
detach后没人收,会内存泄漏
void *my_thread(void *arg)
{
printf("子线程运行---\n");
return NULL;
}
int main(void)
{
pthread_t pthread;
pthread_create(&pthread,NULL,my_thread,NULL);
printf("子线程开始运行---\n");
pthread_detach(pthread);
printf("不阻塞,继续执行主线程\n");
sleep(1);
printf("主线程结束--\n");
return 0;
}
4. pthread_cancel(pthread_t thread)
关键点:
- 只是"请求"取消,不是强制杀死
- 目标线程必须开启取消机制才会响应(默认是开启的)
- 取消是异步的,目标线程可能在**取消点(cancellation point)**才实际退出
⚠️ 大坑:
- 异步取消可能导致资源泄漏(锁没释放、内存没 free)
- 延迟取消更安全,但线程可能卡在非取消点的死循环里,永远退不出
- 取消后必须
join来回收资源!
void *my_thread(void *arg)
{
while (1)
{
printf("子线程运行----\n");
sleep(1);
}
return NULL;
}
int main(void)
{
pthread_t pthread;
pthread_create(&pthread,NULL,my_thread,NULL);
printf("3s后请求取消子线程\n");
sleep(3);
pthread_cancel(pthread);
printf("子线程已取消\n");
sleep(3);
printf("主线程终止\n");
return 0;
}