news 2026/3/12 16:13:40

线程的终止、连接与分离

作者头像

张小明

前端开发工程师

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/3/11 3:21:24

语音克隆合规声明模板:商业使用前获取授权的标准流程

语音克隆合规声明模板&#xff1a;商业使用前获取授权的标准流程 在AI生成内容爆发式增长的今天&#xff0c;我们不仅能“写”出文章、“画”出图像&#xff0c;甚至可以“说”出一段与真人无异的声音。语音合成技术已悄然迈入高保真、个性化的新阶段&#xff0c;尤其是零样本语…

作者头像 李华
网站建设 2026/3/12 7:39:29

Docker容器化部署GLM-TTS:实现环境隔离与快速迁移

Docker容器化部署GLM-TTS&#xff1a;实现环境隔离与快速迁移 在语音合成技术飞速发展的今天&#xff0c;零样本语音克隆、情感控制和多语言支持已成为新一代TTS系统的核心竞争力。像GLM-TTS这类基于大模型的端到端语音生成框架&#xff0c;已经能够仅凭几秒钟的参考音频&#…

作者头像 李华
网站建设 2026/3/12 11:40:01

中文标点符号的作用被忽视?正确使用提升语调停顿效果

中文标点符号的作用被忽视&#xff1f;正确使用提升语调停顿效果 在智能语音助手越来越“能说会道”的今天&#xff0c;很多人以为语音合成的质量完全取决于模型参数和音色选择。但如果你听过一段机械式朗读的有声书——句子连成一片、疑问句听不出疑问、感叹句毫无情绪起伏——…

作者头像 李华
网站建设 2026/3/11 17:19:35

【学习系列】SAP RAP 27:使用OAuth 2.0 SAML 的认证方式消费OData服务

前言 在上一篇中介绍了如何消费标准的OData服务,但是使用的是Basic认证的方式,这样会导致业务对象的创建都是由技术通信用户执行的,而使用OAuth 2.0的认证机制,可以将执行用户的身份被传递到被调用环境,从而使业务对象的创建者为实际的业务执行者,这种认证方式的改变只需…

作者头像 李华
网站建设 2026/3/11 11:38:30

es连接工具深度剖析:底层通信机制与重试策略

从连接池到重试机制&#xff1a;深入理解 Elasticsearch 客户端的稳定性设计在构建现代可观测性系统或实时搜索服务时&#xff0c;Elasticsearch 几乎是绕不开的技术选型。但真正决定其稳定性的&#xff0c;往往不是集群本身&#xff0c;而是客户端——那个看似简单的“连接工具…

作者头像 李华
网站建设 2026/3/11 22:33:09

USB转485驱动与半双工通信机制通俗解释

USB转485驱动与半双工通信机制&#xff1a;从原理到实战的深度拆解在工业现场&#xff0c;你是否遇到过这样的场景&#xff1f;一台崭新的笔记本电脑站在控制柜前束手无策——没有串口&#xff0c;无法连接那些写着“Modbus RTU”的温湿度传感器、电表或PLC。而这些设备明明工作…

作者头像 李华