《线程终止函数详解:pthread_join / detach / cancel 使用指南》

线程终止(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,失败返回错误码(如 ESRCHEINVAL)。

三、用途与场景

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 发送一个取消请求,目标线程是否会终止取决于两个设置:

  1. 取消状态(enable/disable)
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);  // 启用取消(默认)
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); // 禁用取消
  1. 取消类型
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_joinpthread_detachpthread_cancel 三个函数整理在一张对照表里的总结,简洁明了、方便记忆:

pthread_join / pthread_detach / pthread_cancel 对照表

函数名作 用主要参数返回值适用场景特别说明
pthread_join等待一个线程结束,并获取返回值pthread_t tid, void** retval0 成功,非0 错误主线程等待子线程结束不能用于已 detach 的线程;*retval 可判断是否是 PTHREAD_CANCELED
pthread_detach将线程设置为分离状态,自动回收pthread_t tid0 成功,非0 错误不需要等待该线程,自动回收资源一旦 detach,不能再使用 join
pthread_cancel请求取消线程的执行pthread_t tid0 成功,非0 错误想中止一个正在运行的线程线程要到达“取消点”才会真正终止,如 sleep()read()pthread_testcancel()

示例用途快速理解:

  • join 你想等线程干完活,然后拿到它的返回结果。
  • detach 线程自己跑完就算了,不等它,不收尸。
  • cancel 主动打断一个线程(例如发现它跑偏了),请求它尽快结束。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值