news 2026/4/27 19:03:24

线程的终止、连接与分离

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
线程的终止、连接与分离

文章目录

  • 线程的终止
    • pthread_exit()
      • 函数原型
        • 参数
    • return
    • pthread_cancel()
    • 进程终止
  • 线程的连接
    • pthread_join()
      • 函数原型
        • 参数
        • 返回值
  • 线程的分离
    • 两种线程对比
    • 设置线程分离方式
    • 创建后分离(动态分离)
      • pthread_detach
        • 函数原型
        • 主线程中分离
        • 在线程内部分离自己
    • 创建时分离(推荐)
      • pthread_attr_setdetachstate
        • 函数原型
        • 参数
        • 返回值
  • 线程生命周期
线程创建 (pthread_create) ↓ 线程执行 (start_routine) ↓ 线程终止 → 方式1: pthread_exit() 方式2: 从入口函数return 方式3: 被取消 (pthread_cancel) 方式4: 进程终止 ↓ 线程回收 → 可连接线程(joinable): 必须pthread_join() 分离线程(detached): 自动回收

线程的终止

  • 线程终止有4种方式:
    • pthread_exit()
    • 从入口函数return
    • pthread_cancel
    • 进程终止

pthread_exit()

  • 若主线程调用 pthread_exit,主线程退出但子线程仍可继续运行
  • 线程执行完入口函数后,等价于调用 pthread_exit(返回值)

函数原型

#include<pthread.h>voidpthread_exit(void*retval);
参数
  • retval 是线程的退出状态(可被 pthread_join 捕获)
#include<pthread.h>#include<stdio.h>#include<stdlib.h>#include<errno.h>void*func(void*arg){printf("Hello thread!\n");pthread_exit(NULL);//调用 pthread_exit(),指定一个退出状态值}intmain(intargc,constchar*argv[]){pthread_ttid;intret=pthread_create(&tid,NULL,func,NULL);if(ret!=0){errno=ret;perror("pthread_create");exit(EXIT_FAILURE);}printf("tid=%lu\n",tid);pthread_join(tid,NULL);return0;}

return

  • start_routine()的 return语句返回( 相当于调用pthread_exit()
void*thread_func(void*arg){// ... 线程工作 ...return(void*)42;// 效果等同于pthread_exit}

pthread_cancel()

  • 线程被取消
  • 取消是异步的:被取消线程可能不会立即终止
  • 线程可以设置取消状态和取消类型来控制是否响应取消、以及在何时点响应
  • 被取消的线程,其退出状态为 PTHREAD_CANCELED(通常是一个特殊值,如(void*)-1)
  • 嵌入式系统慎用:可能导致资源未正确释放(如未解锁互斥锁)
#include<pthread.h>#include<stdio.h>#include<stdlib.h>#include<errno.h>#include<unistd.h>void*func(void*arg){printf("Hello thread!\n");sleep(10);printf("thread done.\n");//由于线程被主线程取消,所以这里不会被执行pthread_exit(NULL);}intmain(intargc,constchar*argv[]){pthread_ttid;intret=pthread_create(&tid,NULL,func,NULL);if(ret!=0){errno=ret;perror("pthread_create");exit(EXIT_FAILURE);}sleep(1);pthread_cancel(tid);// 1秒后取消printf("tid=%lu\n",tid);pthread_join(tid,NULL);return0;}

进程终止

在线程中调用 exit() 会终止整个进程,这是非常危险的操作,通常应避免

#include<pthread.h>#include<stdio.h>#include<stdlib.h>#include<errno.h>void*func(void*arg){printf("Hello thread!\n");exit(1);// 进程被终止,将导致所有线程终止}intmain(intargc,constchar*argv[]){pthread_ttid;intret=pthread_create(&tid,NULL,func,NULL);if(ret!=0){errno=ret;perror("pthread_create");exit(EXIT_FAILURE);}printf("tid=%lu\n",tid);pthread_join(tid,NULL);return0;}

线程的连接

pthread_join()

  • 阻塞等待指定线程终止,并获取其退出状态(仅对「可结合线程」有效)
    • 等待线程终止:阻塞调用线程,直到目标线程结束
    • 获取线程返回值:接收线程的退出状态(void* 值)
    • 释放线程资源:回收已终止线程的系统资源(如栈空间)
  • 每个可连接线程必须被pthread_join()一次且仅一次,否则会造成资源泄漏
  • 如果不对可连接线程调用pthread_join(),线程终止后会变成僵尸线程(类似僵尸进程),占用系统资源

调用后会阻塞,直到目标线程终止;若线程已终止,立即返回

函数原型

#include<pthread.h>intpthread_join(pthread_tthread,void**retval);
参数
  • thread:要等待的线程 ID
  • retval:输出参数,接收线程的退出状态(pthread_exit 的参数或入口函数返回值)
返回值
  • 成功返回 0
  • 失败返回错误码
    • ESRCH:找不到指定的线程ID(线程已结束或被误写)
    • EINVAL:线程是分离的(detached),不可连接
    • EDEADLK:死锁(例如,线程等待自己)
#include<pthread.h>#include<stdio.h>#include<stdlib.h>#include<string.h>void*func(void*arg){printf("Hello thread!\n");pthread_exit(NULL);}intmain(intargc,constchar*argv[]){pthread_ttid;intret=pthread_create(&tid,NULL,func,NULL);if(ret!=0){fprintf(stderr,"pthread_create:%s\n",strerror(ret));exit(EXIT_FAILURE);}printf("tid=%lu\n",tid);ret=pthread_join(tid,NULL);if(ret!=0){fprintf(stderr,"pthread_join:%s\n",strerror(ret));exit(EXIT_FAILURE);}return0;}

线程的分离

  • 线程的执行顺序是不确定的
  • 线程是可连接的,或者是分离的
    • 可连接的调用pthread_join()等待线程终止并获取退出状态
    • 分离的线程其资源会自动放回系统
  • 分离线程无法被<font style="color:rgb(0, 0, 0);">pthread_join</font>等待,调用会报错

两种线程对比

特性可连接线程 (Joinable)分离线程 (Detached)
资源回收必须显式调用pthread_join()自动回收,线程终止后立即释放资源
获取返回值可通过pthread_join()获取无法获取返回值
默认状态pthread_create()创建时的默认状态需要显式设置
适用场景需要知道线程执行结果一次性后台任务,不关心结果
(如日志线程)

设置线程分离方式

  • 设置线程分离状态的方式:
    • 创建后分离(动态分离)
    • 创建时分离(推荐)

创建后分离(动态分离)

pthread_detach

  • 将线程设为「分离状态」,线程终止后自动释放资源(无需 pthread_join)
函数原型
#include<pthread.h>intpthread_detach(pthread_tthread);
  • 返回值:成功返回 0,失败返回错误码
主线程中分离
pthread_ttid;pthread_create(&tid,NULL,thread_func,NULL);pthread_detach(tid);// 主线程中分离
在线程内部分离自己

pthread_self()获取当前执行线程的唯一标识符(线程 ID)

// 在线程内部分离自己void*thread_func(void*arg){pthread_detach(pthread_self());// ... 线程工作 ...returnNULL;}
#include<pthread.h>#include<stdio.h>#include<stdlib.h>#include<errno.h>#include<unistd.h>void*func(void*arg){pthread_detach(pthread_self());//设置线程为分离属性printf("detach thread.\n");pthread_exit(NULL);}intmain(intargc,constchar*argv[]){pthread_ttid;intret=pthread_create(&tid,NULL,func,NULL);if(ret!=0){errno=ret;perror("pthread_create");exit(EXIT_FAILURE);}// pthread_detach(tid); //也可以在主线程当中设置创建线程的分离属性printf("tid=%lu\n",tid);sleep(1);return0;}

如果线程在pthread_detach()调用前就终止了,可能会变成僵尸线程

创建时分离(推荐)

  • 最安全的方式,确保线程一开始就是分离的
pthread_attr_tattr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);pthread_ttid;pthread_create(&tid,&attr,thread_func,NULL);pthread_attr_destroy(&attr);// 销毁属性对象

pthread_attr_setdetachstate

函数原型
#include<pthread.h>intpthread_attr_setdetachstate(pthread_attr_t*attr,intdetachstate);
参数
  • attr:指向已初始化的线程属性对象(pthread_attr_t)的指针
  • detachstate:要设置的分离状态,仅支持两个取值:
    • PTHREAD_CREATE_JOINABLE(默认):可结合状态
    • PTHREAD_CREATE_DETACHED:分离状态
返回值
  • 成功:返回0
  • 失败:返回非 0 的错误码(常见错误:EINVAL,如attr 无效或 detachstate取值非法)
#include<pthread.h>#include<stdio.h>#include<stdlib.h>#include<string.h>void*thread_func(void*arg){printf("分离线程执行中(tid=%lu)\n",(unsignedlong)pthread_self());// 分离线程终止后,资源自动回收pthread_exit(NULL);}intmain(){pthread_attr_tattr;// 1. 初始化属性对象if(pthread_attr_init(&attr)!=0){perror("pthread_attr_init failed");exit(1);}// 2. 设置分离状态为 DETACHEDif(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED)!=0){fprintf(stderr,"pthread_attr_setdetachstate failed: %s\n",strerror(ret));pthread_attr_destroy(&attr);exit(1);}// 3. 创建分离线程pthread_ttid;if(pthread_create(&tid,&attr,thread_func,NULL)!=0){perror("pthread_create failed");pthread_attr_destroy(&attr);exit(1);}printf("创建分离线程(tid=%lu)\n",(unsignedlong)tid);// 4. 销毁属性对象pthread_attr_destroy(&attr);// 主线程休眠,确保分离线程执行完成sleep(1);return0;}

嵌入式开发中的特殊考虑:

资源有限性:在内存受限的嵌入式系统中,分离线程可以减少资源泄漏的风险,因为不需要记住去join每个线程

实时性要求:分离线程可以立即释放资源,避免因等待join而延迟其他任务的执行

除非需要获取线程的返回值,否则优先使用分离线程

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 17:09:24

零经验怎么入门网络安全学习?看这一篇文章就够了!

零基础怎么开始学网络安全 ​ ​一、学习建议 1.了解基础概念&#xff1a; 开始之前&#xff0c;了解网络安全的基本概念和术语是很重要的。你可以查找网络安全入门教程或在线课程&#xff0c;了解网络安全领域的基本概念&#xff0c;如黑客、漏洞、攻击类型等。 2.网络基础…

作者头像 李华
网站建设 2026/4/20 23:23:33

API密钥管理体系设计:保障服务调用的安全性与可追溯性

API密钥管理体系设计&#xff1a;保障服务调用的安全性与可追溯性 在AI模型逐渐从实验室走向生产环境的今天&#xff0c;语音合成、自然语言处理等能力正以API的形式被广泛集成到各类应用中。以GLM-TTS为例&#xff0c;它已经具备WebUI交互、批量推理和流式输出等功能&#xf…

作者头像 李华
网站建设 2026/4/27 0:31:11

Rust 生命周期,三巨头之一

在 Rust 编程中&#xff0c;所有权&#xff08;Ownership&#xff09;、借用&#xff08;Borrowing&#xff09;和生命周期&#xff08;Lifetime&#xff09;是三大核心特性&#xff0c;它们共同构成了 Rust 内存安全的基石。其中&#xff0c;生命周期相对抽象&#xff0c;却是…

作者头像 李华
网站建设 2026/4/24 9:04:04

KAN:为什么以及它是如何工作的?深入探讨

原文&#xff1a;towardsdatascience.com/kan-why-and-how-does-it-work-a-deep-dive-1adab4837fa3 https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/770c93e12c8c2a5af60c4fd3c1ed6ddc.png 神经网络能否发现新的物理学&#xff1f;(由作者…

作者头像 李华
网站建设 2026/4/21 20:27:09

保持梯度流动

原文&#xff1a;towardsdatascience.com/keep-the-gradients-flowing-5b9bf0098e3d https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/bb0a649375c5f67394c1f6a552ec4101.png AI 图像生成&#xff0c;描绘神经网络中的梯度流动 近年来&am…

作者头像 李华