嵌入式多线程开发: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/25 6:25:48 阅读更多 →
张家口本土经营世纪腾达实木门店众多,究竟哪家才是靠谱之选?

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

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

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

最新新闻

Agent Memory 全景盘点:从 ChatGPT 的「做梦」到 Claude 的文件系统,TaoToken 统一 Key 下的 2026 智能体记忆架构拆解

Agent Memory 全景盘点:从 ChatGPT 的「做梦」到 Claude 的文件系统,TaoToken 统一 Key 下的 2026 智能体记忆架构拆解

/* 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 8:36:01 阅读更多 →
看清 OpenClaw 每一步:扣子罗盘 Trace 全新上线,TaoToken 统一 Key 配置实战

看清 OpenClaw 每一步:扣子罗盘 Trace 全新上线,TaoToken 统一 Key 配置实战

/* 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 8:36:01 阅读更多 →
金融系统架构设计:账务核心、幂等机制与分布式事务实践

金融系统架构设计:账务核心、幂等机制与分布式事务实践

做金融服务业的后端系统,和做电商、内容平台完全是两码事。很多人以为金融系统就是“多几个接口、加密字段、对个账”,其实真正动手落地的时候,你会发现账务一致性、资金安全、合规审计、幂等防重这些环节每一个都足以让一个团队翻车。这个“…

2026/9/25 8:36:01 阅读更多 →
Agentic 调度实战:CLI + Kubernetes 编排 Agent 工作负载

Agentic 调度实战:CLI + Kubernetes 编排 Agent 工作负载

1. 从 "ax" 这个标题说起:一个被低估的 Agentic 调度入口第一次看到 "ax" 这个标题,很多人会以为是某个命令行工具的缩写,或者某个内部项目的代号。但把关键词铺开看——agentic、orchestrator、Kubernetes、CLI——就能…

2026/9/25 8:36:01 阅读更多 →
Windows查硬盘序列号的正确姿势:绕过WMIC陷阱

Windows查硬盘序列号的正确姿势:绕过WMIC陷阱

1. 为什么查硬盘序列号这件事,90%的人从第一步就错了?你是不是也试过在百度搜“怎么查硬盘序列号”,点开前五条结果,复制粘贴一通命令,结果要么弹出红色报错,要么返回一堆乱码,甚至直接跳出“WM…

2026/9/25 8:36:01 阅读更多 →
Zsteg:CTF中LSB隐写探测与精准提取实战指南

Zsteg:CTF中LSB隐写探测与精准提取实战指南

1. 为什么Zsteg是CTF Misc赛道里真正能“秒破图”的LSB隐写探测器在CTF Misc题型中,你肯定遇到过这种场景:拿到一张看似普通的PNG或BMP图片,题目提示“flag藏在图像里”,但用binwalk -e扫不出文件,strings翻到眼花也没…

2026/9/25 8:35:01 阅读更多 →

日新闻

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 阅读更多 →