news 2026/5/1 7:10:36

32、Linux线程编程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
32、Linux线程编程

Linux线程编程

一、线程核心理论基础

1. 线程是什么?

  • 定义:线程是进程内的执行单元,也被称为“轻量级进程”(Lightweight Process),隶属于某个进程,共享进程的资源(代码段、数据段、文件描述符等)。
  • 核心作用:实现并发执行,将耗时任务拆分到多个线程并行处理,提升程序效率(如视频渲染、网络请求并发处理)。

2. 线程的核心特征

特征说明
资源分配进程是系统最小资源分配单位,线程不单独分配资源(共享进程资源)
执行单位线程是系统最小执行单位,CPU调度的基本对象
层级关系进程内线程平级,默认存在一个“主线程”(main函数所在线程)
资源共享线程间共享进程的全局变量、静态变量、文件描述符等,仅栈区(8MB)独立
稳定性线程不稳定:一个线程崩溃会导致整个进程退出;进程相对稳定,互不影响
创建开销线程创建仅需开辟独立栈区(8MB),进程创建需分配3GB虚拟地址空间,开销更大
并发度线程并发度高于进程,同一进程内线程切换无需切换地址空间,效率更高

3. 线程与进程的核心区别

对比维度线程(Thread)进程(Process)
资源分配共享所属进程资源,无独立地址空间独立地址空间,资源独立(代码段、数据段等)
创建/切换开销小(仅开辟栈区)大(分配完整地址空间)
通信方式直接访问共享变量,通信简单需通过IPC(管道、消息队列等),通信复杂
稳定性低(线程崩溃导致进程退出)高(进程间相互隔离)
并发效率高(线程切换无需地址空间切换)低(进程切换开销大)

4. 线程编程核心流程(POSIX标准)

  1. 创建多线程:通过pthread_create创建子线程,指定线程执行函数;
  2. 线程任务执行:子线程在回调函数中完成具体任务(资源操作、计算等);
  3. 线程资源回收:通过pthread_join(阻塞回收)或pthread_detach(自动回收)释放线程资源,避免内存泄漏。

5. 关键线程函数详解

POSIX线程函数库(libpthread)提供了线程操作的核心接口,以下是常用函数说明:

函数原型功能描述
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)创建子线程
-thread:输出参数,存储新线程ID
-attr:线程属性(默认NULL)
-start_routine:线程回调函数(执行入口)
-arg:回调函数参数
- 返回值:成功0,失败返回错误码
pthread_t pthread_self(void)获取当前线程ID
- 返回值:当前线程的ID(unsigned long类型,打印用%lu
void pthread_exit(void *retval)子线程主动退出
-retval:线程退出状态(返回给主线程)
int pthread_cancel(pthread_t thread)主线程取消指定子线程
-thread:目标线程ID
- 返回值:成功0,失败返回错误码
int pthread_join(pthread_t thread, void **retval)阻塞回收子线程资源
-thread:待回收线程ID
-retval:接收子线程退出状态
- 返回值:成功0,失败返回错误码
int pthread_detach(pthread_t thread)设置线程分离属性(退出后自动回收资源)
- 无需主线程调用pthread_join

6. 线程查看命令

# 查看系统所有线程(PID:进程ID,LWP:线程ID,COMM:线程名称)ps-eLo pid,ppid,lwp,stat,comm# 查看线程详细信息(含CPU占用、内存等)ps-eLf

二、实战代码解析(8个核心案例)

以下结合8个实战代码,从基础到进阶,逐步掌握线程编程技巧(所有代码需链接pthread库编译:gcc 文件名.c -o 文件名 -lpthread)。

案例01:创建多线程(01pthread.c)

功能:创建2个子线程,分别执行不同任务(发视频、接收控制)
#include<stdio.h>#include<pthread.h>#include<stdlib.h>#include<unistd.h>#include<string.h>// 线程1回调函数:发视频void*thread_function(void*arg){while(1){printf("发视频...\n");sleep(1);// 每隔1秒执行一次}returnNULL;}// 线程2回调函数:接收控制void*thread_function2(void*arg){while(1){printf("接受控制...\n");sleep(1);}returnNULL;}intmain(){pthread_tthread_id;// 线程1 IDpthread_tthread_id2;// 线程2 ID// 创建线程1pthread_create(&thread_id,NULL,thread_function,NULL);// 创建线程2pthread_create(&thread_id2,NULL,thread_function2,NULL);// 主线程阻塞(避免主线程退出导致子线程终止)while(1){sleep(1);}return0;}
关键说明:
  1. pthread_create参数:线程ID指针、默认属性(NULL)、回调函数、回调函数参数(NULL);
  2. 主线程需保持运行(while(1)),否则主线程退出后,整个进程终止,子线程也会被销毁;
  3. 编译命令:gcc 01pthread.c -o 01pthread -lpthread
  4. 运行结果:两个子线程交替输出“发视频…”和“接受控制…”,实现并发执行。

案例02:获取线程ID(02pthread_self.c)

功能:通过pthread_self()获取主线程和子线程的ID
#include<stdio.h>#include<pthread.h>#include<unistd.h>#include<stdlib.h>#include<string.h>void*th1(void*arg){while(1){// 打印子线程1 ID(%lu对应unsigned long类型)printf("发视频...tid:%lu\n",pthread_self());sleep(1);}returnNULL;}void*th2(void*arg){while(1){printf("接受控制...tid:%lu\n",pthread_self());sleep(1);}returnNULL;}intmain(){pthread_ttid1,tid2;pthread_create(&tid1,NULL,th1,NULL);pthread_create(&tid2,NULL,th2,NULL);// 打印主线程IDwhile(1){printf("main tid:%lu\n",pthread_self());sleep(1);}return0;}
关键说明:
  1. pthread_self()无参数,返回当前线程的ID(类型为pthread_t,建议用%lu格式化输出);
  2. 运行结果:主线程和两个子线程分别输出各自的ID,可通过ps -eLo lwp,comm验证线程是否存在。

案例03:线程退出(03pthread_exit.c)

功能:子线程通过pthread_exit()主动退出,主线程运行指定次数后退出
#include<stdio.h>#include<pthread.h>#include<stdlib.h>#include<unistd.h>#include<string.h>void*th(void*arg){while(1){printf("sub_th %lu\n",pthread_self());sleep(1);}pthread_exit(NULL);// 子线程主动退出(此处因while(1)无法执行到,仅作演示)}intmain(){pthread_ttid;pthread_create(&tid,NULL,th,NULL);inti=8;// 主线程运行8秒后退出while(i--){printf("main_th %lu\n",pthread_self());sleep(1);}return0;}
关键说明:
  1. pthread_exit(NULL):子线程主动退出,参数为退出状态(NULL表示无返回值);
  2. 注意:主线程退出后,子线程会被强制终止(即使子线程有while(1));
  3. 运行结果:主线程输出8次后退出,子线程同时终止。

案例04:取消线程(04phread_cancel.c)

功能:主线程通过pthread_cancel()取消子线程
#include<stdio.h>#include<stdlib.h>#include<pthread.h>#include<unistd.h>#include<string.h>void*thread_func(void*arg){while(1){printf("subth %lu\n",pthread_self());sleep(1);}}intmain(){pthread_ttid;pthread_create(&tid,NULL,thread_func,NULL);inti=0;while(1){printf("main th %lu\n",pthread_self());sleep(1);i++;if(i==2){// 运行2秒后,主线程取消子线程pthread_cancel(tid);printf("子线程已取消\n");}}return0;}
关键说明:
  1. pthread_cancel(tid):向指定子线程发送取消请求,子线程在“取消点”(如sleepprintf等系统调用)响应;
  2. 运行结果:子线程输出2次后被取消,主线程继续运行;
  3. 注意:pthread_cancel仅发送请求,若子线程无取消点(如纯计算循环),需手动调用pthread_testcancel()设置取消点。

案例05:线程资源回收(05pthread_jion.c)

功能:主线程通过pthread_join()阻塞等待子线程完成,回收资源
#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<string.h>#include<pthread.h>void*th(void*arg){inti=5;while(i--){printf("workth,%lu\n",pthread_self());sleep(1);}returnNULL;}intmain(intargc,char**argv){pthread_ttid;pthread_create(&tid,NULL,th,NULL);// 阻塞等待子线程tid完成,回收其资源pthread_join(tid,NULL);printf("子线程已结束,主线程退出\n");return0;}
关键说明:
  1. pthread_join(tid, NULL):主线程阻塞,直到子线程tid退出,避免子线程成为“僵尸线程”(资源未回收);
  2. 第二个参数为NULL,表示不关心子线程的退出状态;
  3. 运行结果:子线程输出5次后退出,主线程打印提示后退出。

案例06:获取线程返回值(06pthread_jionret.c)

功能:子线程动态分配内存并返回数据,主线程通过pthread_join()获取返回值并释放内存
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<pthread.h>#include<unistd.h>void*th(void*arg){// 动态分配内存(子线程栈区数据不能返回,会随线程退出释放)char*str=(char*)malloc(20);strcpy(str,"我要灭亡了");returnstr;// 返回动态内存地址}intmain(intargc,char*argv[]){pthread_ttid;pthread_create(&tid,NULL,th,NULL);void*ret=NULL;// 回收子线程,获取返回值(ret指向子线程分配的内存)pthread_join(tid,&ret);printf("子线程返回值:%s\n",(char*)ret);free(ret);// 释放子线程分配的内存,避免内存泄漏return0;}
关键说明:
  1. 子线程返回值不能是栈区变量(线程退出后栈区释放),需用malloc动态分配内存;
  2. 主线程通过pthread_join的第二个参数&ret接收返回值,使用后需手动free
  3. 运行结果:主线程打印子线程返回的字符串“我要灭亡了”。

案例07:传递结构体参数(07.c)

功能:主线程向子线程传递结构体参数,子线程打印并返回结构体地址
#include<stdio.h>#include<pthread.h>#include<stdlib.h>#include<unistd.h>#include<string.h>// 定义结构体(存储用户信息)typedefstruct{charname[20];intage;charaddress[50];}PER;void*th(void*arg){// 将void*类型转换为结构体指针PER*p=(PER*)arg;printf("子线程接收的信息:\n");printf("name:%s\n",p->name);printf("age:%d\n",p->age);printf("address:%s\n",p->address);
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 0:33:39

Dify音频时长卡点问题全解析,专家亲授4步优化法

第一章&#xff1a;Dify 1.7.0 音频时长限制概述Dify 1.7.0 版本在音频处理模块中引入了更严格的时长控制机制&#xff0c;旨在优化资源调度与提升系统稳定性。该版本默认限制单次上传或处理的音频文件时长不得超过300秒&#xff08;5分钟&#xff09;&#xff0c;超出此范围的…

作者头像 李华
网站建设 2026/4/23 16:50:07

从崩溃到稳定仅需一步:Dify混合检索缓存清理最佳实践

第一章&#xff1a;从崩溃到稳定的转折点系统在经历连续72小时的异常宕机后&#xff0c;终于迎来了关键的修复契机。这次故障源于一次未经充分测试的配置推送&#xff0c;导致服务链路中核心网关节点过载崩溃。团队在紧急回滚后&#xff0c;开始深入分析日志与监控数据&#xf…

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

【大模型】happy-llm笔记

happy-llm是datawhale发布的一套关于llm的教程&#xff0c;链接在此&#xff0c;今天看了这套课程的第二章到第四章的内容&#xff0c;对自己一直以来好奇的一些llm相关的问题有了解答。 将我遇到的问题整理到下面&#xff0c;部分可能没有回答&#xff0c;感兴趣的同学可以去原…

作者头像 李华
网站建设 2026/4/30 18:28:25

为什么顶尖科技公司都在强制Agent镜像签名?真相来了

第一章&#xff1a;为什么顶尖科技公司都在强制Agent镜像签名&#xff1f;真相来了在现代云原生架构中&#xff0c;Agent 镜像作为连接终端与控制平面的核心组件&#xff0c;其安全性直接关系到整个系统的可信边界。近年来&#xff0c;Google、Meta、Netflix 等顶尖科技公司纷纷…

作者头像 李华
网站建设 2026/4/20 3:04:29

滴滴企业版和高德企业版哪个好?2025年企业出行平台深度对比

在企业数字化转型加速的当下&#xff0c;企业用车管理平台的选择成为众多企业管理者关注的焦点。滴滴企业版和高德企业版作为国内主流的企业出行服务平台&#xff0c;各自拥有独特的产品优势与服务特色。据2025年企业出行调研报告显示&#xff0c;超过78%的企业在选择出行平台时…

作者头像 李华
网站建设 2026/4/23 15:21:08

wordpress原生主题二次开发常用到的一些知识点

WordPress原生主题二次开发时&#xff0c;下面这些“高频知识点”建议先吃透。它们既能帮你快速定位要改的文件&#xff0c;也能避免破坏升级路径&#xff0c;90%的日常需求都能覆盖。 模板层级(Template Hierarchy) 先判断“WordPress现在会加载谁?”——同一类页面可以有多…

作者头像 李华