嵌入式多线程开发:pthread 线程与互斥锁实战
嵌入式多线程开发pthread 线程与互斥锁实战一、引言上一篇文章我们讨论了fork多进程开发。进程固然好——每个进程独立地址空间崩溃不互相影响——但创建开销大、进程间通信IPC麻烦。在很多嵌入式场景中我们需要轻量级的并行这时多线程就登场了。线程Thread是共享同一进程地址空间的执行流。多个线程之间切换开销远小于进程切换而且可以直接访问同一块内存通信几乎零成本——但也正因如此必须用互斥锁等手段保护共享数据。本文从pthread的创建讲起深入互斥锁的原理与死锁排查最后给出一个传感器数据采集并发的实战模型。二、线程 vs 进程一张表看懂对比维度进程线程创建开销大分配独立地址空间小共享地址空间切换开销大切换页表小只切换寄存器和栈内存共享IPC 手段管道/共享内存天然共享全局变量和堆崩溃影响不影响其他进程一个线程崩溃可能拖垮整个进程适用场景隔离性要求高高并发、实时性要求高在嵌入式 Linux 中线程的优势尤为明显传感器线程、网络通信线程、数据处理线程可以各司其职互不阻塞。三、创建线程pthread_create#includepthread.hintpthread_create(pthread_t*thread,constpthread_attr_t*attr,void*(*start_routine)(void*),void*arg);看起来参数多拆解一下thread输出参数保存新线程的 IDattr线程属性NULL 表示默认start_routine线程入口函数必须是void* func(void* arg)签名arg传给入口函数的参数编译时需要链接 pthread 库gcc-oapp main.c-lpthread基础示例#includestdio.h#includepthread.h#includeunistd.hvoid*sensor_task(void*arg){intid*(int*)arg;for(inti0;i5;i){printf([传感器%d] 第%d次采样\n,id,i1);sleep(1);}printf([传感器%d] 采集结束\n,id);returnNULL;}intmain(void){pthread_ttid1,tid2;intid11,id22;pthread_create(tid1,NULL,sensor_task,id1);pthread_create(tid2,NULL,sensor_task,id2);// 主线程等待两个子线程结束pthread_join(tid1,NULL);pthread_join(tid2,NULL);printf(所有传感器采集完成\n);return0;}pthread_join会阻塞当前线程直到目标线程结束——类似于进程中的waitpid。四、互斥锁保护共享数据多线程同时访问同一变量时会出现竞态条件Race Condition。想象两个线程同时对counter操作线程A: 读 counter(0) → 加1(1) → 写 counter(1) 线程B: 读 counter(0) → 加1(1) → 写 counter(1)本应是 2结果却是 1——这就是数据竞争。解决方式是互斥锁Mutex。#includepthread.hpthread_mutex_tlockPTHREAD_MUTEX_INITIALIZER;intshared_counter0;void*worker(void*arg){for(inti0;i100000;i){pthread_mutex_lock(lock);// 加锁shared_counter;// 临界区pthread_mutex_unlock(lock);// 解锁}returnNULL;}互斥锁像厕所的锁——一个人进去了就锁门别人在外面等着。出来解锁后下一个人才能进去。互斥锁的四种操作函数行为pthread_mutex_lock阻塞等待直到拿到锁pthread_mutex_trylock立即返回拿不到锁返回 EBUSYpthread_mutex_unlock释放锁pthread_mutex_destroy销毁锁用动态方式创建的静态初始化用PTHREAD_MUTEX_INITIALIZER动态初始化用pthread_mutex_init。五、死锁当两把锁互相等待这是多线程编程中最让人头疼的问题。看这段代码pthread_mutex_tlockAPTHREAD_MUTEX_INITIALIZER;pthread_mutex_tlockBPTHREAD_MUTEX_INITIALIZER;// 线程1void*thread1(void*arg){pthread_mutex_lock(lockA);// 拿到 Asleep(1);// 给线程2时间去拿 Bpthread_mutex_lock(lockB);// 等待 B...// ...}// 线程2void*thread2(void*arg){pthread_mutex_lock(lockB);// 拿到 Bsleep(1);// 给线程1时间去拿 Apthread_mutex_lock(lockA);// 等待 A...// ...}结果线程1 持有 A 等 B线程2 持有 B 等 A——谁也等不到谁死锁。避免死锁的黄金法则固定加锁顺序所有线程必须按相同顺序获取多把锁限制锁粒度锁保护的代码越少越好使用pthread_mutex_trylock拿不到就放弃稍后重试超时机制部分 pthread 实现支持pthread_mutex_timedlock固定加锁顺序举例// 无论哪个线程都先锁 lockA 再锁 lockBpthread_mutex_lock(lockA);pthread_mutex_lock(lockB);// 临界区...pthread_mutex_unlock(lockB);pthread_mutex_unlock(lockA);六、实战传感器采集 线程池模型下面是一个简化版的多线程传感器采集架构#includestdio.h#includestdlib.h#includepthread.h#includeunistd.h#defineSENSOR_COUNT3pthread_mutex_tdata_lockPTHREAD_MUTEX_INITIALIZER;// 共享数据缓冲区typedefstruct{floattemperature;floathumidity;floatpressure;intupdated;}SensorData;SensorData g_data{0};void*temp_sensor(void*arg){(void)arg;while(1){pthread_mutex_lock(data_lock);g_data.temperature25.0(rand()%100)/10.0;g_data.updated1;pthread_mutex_unlock(data_lock);sleep(2);}returnNULL;}void*report_thread(void*arg){(void)arg;while(1){pthread_mutex_lock(data_lock);if(g_data.updated){printf([上报] 温度%.1f°C\n,g_data.temperature);g_data.updated0;}pthread_mutex_unlock(data_lock);sleep(3);}returnNULL;}intmain(void){pthread_tt1,t2;pthread_create(t1,NULL,temp_sensor,NULL);pthread_create(t2,NULL,report_thread,NULL);pthread_join(t1,NULL);pthread_join(t2,NULL);return0;}这个架构很简单但实用采集线程定时更新共享数据上报线程定时读取并上报靠互斥锁保证数据一致性。七、总结多线程编程的核心就三件事创建与回收pthread_create/pthread_join数据保护互斥锁pthread_mutex_lock/unlock死锁避免固定加锁顺序、减小锁粒度、用 trylock在嵌入式 Linux 中线程是并行处理的主力。掌握互斥锁你的程序才能在高并发下稳如磐石。

相关新闻

Light Tips项目入门:PHP开发者必学的基础算法与数据结构

Light Tips项目入门:PHP开发者必学的基础算法与数据结构

Light Tips项目入门:PHP开发者必学的基础算法与数据结构 【免费下载链接】light-tips Some code tips about algorithms, php and more 🔥 项目地址: https://gitcode.com/gh_mirrors/li/light-tips Light Tips是一个专为PHP开发者设计的算法与数…

2026/9/25 5:27:22 阅读更多 →
解锁飞行模式:INAV Configurator中10种飞行模式的设置与实战技巧

解锁飞行模式:INAV Configurator中10种飞行模式的设置与实战技巧

解锁飞行模式:INAV Configurator中10种飞行模式的设置与实战技巧 【免费下载链接】inav-configurator 项目地址: https://gitcode.com/gh_mirrors/in/inav-configurator INAV Configurator是一款强大的开源飞控配置工具,帮助无人机爱好者轻松设置…

2026/9/23 15:18:08 阅读更多 →
张家口本土经营世纪腾达实木门店众多,究竟哪家才是靠谱之选?

张家口本土经营世纪腾达实木门店众多,究竟哪家才是靠谱之选?

在张家口,实木家具市场呈现出一派热闹景象,世纪腾达实木家具更是备受消费者青睐。然而,面对众多经营世纪腾达实木的门店,消费者往往会感到困惑:究竟哪家才是靠谱之选呢?今天,我们就来深入剖析一…

2026/9/18 21:58:50 阅读更多 →

最新新闻

Flink SQL 上线前压测最短闭环:Print Sink 验证正确性 + BlackHole Sink 压性能

Flink SQL 上线前压测最短闭环:Print Sink 验证正确性 + BlackHole Sink 压性能

做 Flink SQL 任务上线前,最怕的就是两眼一抹黑直接丢到生产。数据算得对不对?性能顶不顶得住?等问题暴露出来,往往已经晚了。我这两年一直用的最短闭环方案,就是Print Sink先把结果正确性验证清楚,再切到B…

2026/9/25 5:50:36 阅读更多 →
Canvas粒子系统实战:用纯HTML5打造会流动的爱心特效

Canvas粒子系统实战:用纯HTML5打造会流动的爱心特效

简介:这是一个基于HTML5 Canvas的粒子流动爱心形状动画特效源码包,面向前端开发初学者与Canvas动画爱好者,展示如何用原生Canvas API构建动态粒子系统,并让红色粒子沿预设爱心路径流动、逐渐消散,形成浪漫而引人注目的…

2026/9/25 5:50:36 阅读更多 →
FFmpeg视频信息解析与逐帧导出:从入门到完整工作流

FFmpeg视频信息解析与逐帧导出:从入门到完整工作流

拿到 FFmpeg 的第一步,很多人都是冲着“把视频转成 mp4”或者“压缩视频”去的。但实际用久了你会发现,真正高频的需求其实是另外两件事:一个是搞清楚视频到底是什么来头,编码、分辨率、帧率、码率这些参数到底是多少;…

2026/9/25 5:50:36 阅读更多 →
随机森林OOB误差调优实战:从原理到sklearn降误差

随机森林OOB误差调优实战:从原理到sklearn降误差

做建模的人应该都见过这个场景:训练完随机森林,第一件事不是急着看测试集 AUC,而是先瞄一眼训练日志里的 oob_score。手头没有单独验证集时,袋外误差就是那个免费测试集;有验证集时,它也常被拿来当作模型好…

2026/9/25 5:50:36 阅读更多 →
猛兽派对风灵月影修改器:功能解析与安全使用指南

猛兽派对风灵月影修改器:功能解析与安全使用指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 5:50:36 阅读更多 →
Atlas 300V 24G推理卡部署YOLO指南:从环境搭建到调优

Atlas 300V 24G推理卡部署YOLO指南:从环境搭建到调优

Atlas 这个项目名字,说大不大,说小不小。如果你是因为“atlas部署yolo”和“atlas 300v 24g 是运算加速卡吗”这两个热搜摸进来的,那我估计你跟我当初一样,手里刚好拿到一张华为的 Atlas 300V 推理卡,或者正在选型阶段…

2026/9/25 5:49:36 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →