线程终止(Thread termination)
1.简介——什么是线程
线程简介(Introduction to Threads)
线程(Thread) 是程序执行中的最小单位,是操作系统能够进行运算调度的最小执行单元。一个进程可以包含多个线程,这些线程共享进程的资源(如内存空间、文件句柄等),但每个线程拥有自己的运行栈、程序计数器等。
相比进程,线程创建和切换的开销更小,通信更高效,因此在并发编程中被广泛使用,尤其适用于多核处理器环境下的任务并行处理。
线程的特点:
- 轻量级:与进程相比,占用资源少。
- 共享内存:同一进程内的线程可以访问共享数据。
- 独立调度:每个线程都可以被单独调度执行。
- 适合并发:提高程序执行效率,尤其在 I/O 密集或多任务场景中。
常见应用场景:
- 多任务处理(如下载、播放、界面响应同时进行)
- 服务器并发处理多个客户端请求
- 并行计算加快程序运行速度
而线程终止是指线程完成任务或因某些条件被停止运行,退出其生命周期的过程。线程终止后,其占用的资源将被系统回收。
2.相关函数介绍及使用方法
以下函数都需要导入
#include <pthread.h>
头文件
1.pthread_join()
一、函数简介
pthread_join()
是 POSIX 线程库(pthread
)中用于等待线程结束的函数。当主线程或其他线程调用 pthread_join()
等待某个线程时,当前线程会被阻塞,直到被等待的线程执行完毕并终止。
二、函数原型
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
thread
:要等待的线程 ID(通过pthread_create()
创建时返回)retval
:用于接收目标线程的返回值(可为NULL
,如果不关心返回值)
返回值:
- 成功返回
0
; - 失败返回错误码,例如
ESRCH
(线程不存在)、EINVAL
(线程不可连接)等。
三、使用示例
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
void* thread_func(void* arg) {
printf("Thread running, arg = %d\n", *(int*)arg);
int* result = malloc(sizeof(int));
*result = 1234; // 模拟计算结果
return result;
}
int main() {
pthread_t tid;
int arg = 10;
void* retval;
pthread_create(&tid, NULL, thread_func, &arg);//创建线程
pthread_join(tid, &retval);
printf("Thread returned: %d\n", *(int*)retval);//打印函数返回值
free(retval); // 别忘了释放返回值内存
return 0;
}
输出结果如下图所示:
四、常见用途
- 主线程等待子线程完成任务。
- 控制线程执行顺序。
- 回收线程资源,避免内存泄漏。
2.pthread_detach()
一、函数简介
pthread_detach()
是 POSIX 线程库中用于将线程设置为分离状态(detached state)的函数。
处于分离状态的线程在终止后,其资源会自动释放,不需要也不能使用 pthread_join()
来回收。
二、函数原型
#include <pthread.h>
int pthread_detach(pthread_t thread);
thread
:要设置为分离状态的线程 ID。- 返回值:成功返回
0
,失败返回错误码(如ESRCH
、EINVAL
)。
三、用途与场景
pthread_detach()
通常用于以下两类场景:
- 线程执行任务后不需要返回值,也不需要主线程等待。
- 创建大量线程时,避免资源未释放造成泄露(资源包括线程堆栈、线程描述符等)。
四、使用示例
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void* thread_func(void* arg) {
printf("Detached thread running...\n");
sleep(2);
printf("Detached thread done.\n");
return NULL;
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, thread_func, NULL);
pthread_detach(tid); // 设置为分离状态
printf("Main thread done.\n");
sleep(3); // 等待子线程输出
return 0;
}
输出结果如下图所示:
✅ 总结一句话:
pthread_detach()
用来把线程设置为分离状态,使其在结束后自动释放资源,适合那种“甩出去就不管”的线程。
3.pthread_cancel()
一、函数简介:
pthread_cancel
是 POSIX 线程库中用于取消一个线程的函数。
它的作用是:向目标线程发送一个取消请求,但是否真的终止,取决于目标线程自身的取消状态和类型。
二、函数原型
#include <pthread.h>
int pthread_cancel(pthread_t thread);
- 参数:
thread
:需要被取消的线程 ID(通过pthread_create
获得)。
- 返回值:
- 成功返回
0
,失败返回错误码。
- 成功返回
三、取消原理:
当你调用 pthread_cancel
发送一个取消请求,目标线程是否会终止取决于两个设置:
- 取消状态(enable/disable)
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); // 启用取消(默认)
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); // 禁用取消
- 取消类型
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); // 延迟取消(默认)
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); // 异步取消
- 延迟取消(默认):只有在线程执行到“取消点”时,取消才会生效。
- 异步取消:线程会随时响应取消(⚠️ 比较危险,一般不推荐)。
四、简单使用示例:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void*task(void *ag)
{
printf("线程启动\n");
printf("working....");
//默认取消类型是延迟
sleep(1);
//人为调用取消函数
pthread_testcancel();
printf("threads finished\n");
return NULL;
}
int main(int argc, char const *argv[])
{
//创建线程
pthread_t pid;
pthread_create(&pid,NULL,task,NULL);
//取消子线程
if((pthread_cancel(pid))!=0)
{
perror("pthread_cancel");
}
void *res;
//只是发出一个停止的命令
pthread_join(pid,&res);
if(res==PTHREAD_CANCELED)
{
printf("已经停止\n");
}else
{
printf("线程还没有被取消 exitcode:%ld",(long)res);
}
return 0;
}
输出结果如下图所示:
五、适用场景:
- 用户中断操作后强制终止线程;
- 超时机制中取消长期阻塞线程;
- 资源释放和清理逻辑中(搭配
pthread_cleanup_push
使用)
3.总结
下面是将 pthread_join
、pthread_detach
和 pthread_cancel
三个函数整理在一张对照表里的总结,简洁明了、方便记忆:
pthread_join
/ pthread_detach
/ pthread_cancel
对照表
函数名 | 作 用 | 主要参数 | 返回值 | 适用场景 | 特别说明 |
---|---|---|---|---|---|
pthread_join | 等待一个线程结束,并获取返回值 | pthread_t tid , void** retval | 0 成功,非0 错误 | 主线程等待子线程结束 | 不能用于已 detach 的线程;*retval 可判断是否是 PTHREAD_CANCELED |
pthread_detach | 将线程设置为分离状态,自动回收 | pthread_t tid | 0 成功,非0 错误 | 不需要等待该线程,自动回收资源 | 一旦 detach ,不能再使用 join |
pthread_cancel | 请求取消线程的执行 | pthread_t tid | 0 成功,非0 错误 | 想中止一个正在运行的线程 | 线程要到达“取消点”才会真正终止,如 sleep() 、read() 或 pthread_testcancel() |
示例用途快速理解:
join
: 你想等线程干完活,然后拿到它的返回结果。detach
: 线程自己跑完就算了,不等它,不收尸。cancel
: 主动打断一个线程(例如发现它跑偏了),请求它尽快结束。