本文约4100字,今天继续读书并学习任务间同步及通信。多任务并发是操作系统核心能力,只要存在共享资源、多线程协作场景,竞态条件、数据错乱、优先级反转、死锁等问题就会随之而来。Linux内核面向通用服务器/PC,RT-Thread面向嵌入式实时设备,二者虽然底层同步思想同源(互斥、同步、消息传递),但实现粒度、使用约束、适用场景差异极大。
本文结合《深入Linux内核架构》第五章锁与进程间通信以及官网RT-Thread编程指南第四章任务间同步及通信这两个章节内容,梳理两类系统全部同步、IPC机制,横向对比异同,总结实际开发高频踩坑点。
关注公众号, 即可获得与Linux相关的电子书籍以及常用开发工具,文末有文档清单。
多执行流(CPU/线程/中断)并发读写共享变量,读写操作被调度打断,导致数据不一致。文档经典案例:双进程共享计数器counter,进程1读取数值后被调度切走,进程2修改并覆盖数据,最终序号丢失、文件覆盖。
关键特性:竞态复现概率极低,无法靠测试覆盖,必须从代码加锁防护。
访问共享资源的代码片段,核心约束:同一时刻仅允许一个执行流进入,即互斥访问。
API:rt_hw_interrupt_disable()/rt_hw_interrupt_enable(level),保存恢复中断上下文,支持嵌套。 适用场景:极短临界区(单变量自增)、中断与线程共享资源互斥。
限制:关中断期间外设中断全部屏蔽,长时间持有会丢失硬件信号,实时性崩盘。
底层local_irq_disable()/local_irq_save(flags),衍生锁:spin_lock_irq()、spin_lock_irqsave()。
差异:Linux区分SMP多核场景,关中断仅屏蔽本地CPU,其他CPU仍可并发访问共享变量,必须搭配自旋锁使用;RT-Thread多为单核MCU,关中断即可完全杜绝竞态。
API:rt_enter_critical()/rt_exit_critical(),关闭线程调度,但不屏蔽硬件中断,中断服务程序仍可正常执行。 适用场景:仅线程间共享资源,无中断读写;嵌套计数支持,成对调用。 Linux无对应机制:Linux靠preempt_disable()禁用内核抢占实现同类效果,属于自旋锁配套逻辑,无独立调度锁API。
数据结构spinlock_t,核心逻辑:抢锁失败时忙循环自旋等待,不进入睡眠。 细分衍生:普通自旋锁、_irq关中断版、_bh关软中断版;读写自旋锁rwlock_t。 硬性约束(高频踩坑):
kmalloc、信号量down()等睡眠函数禁止调用);RT-Thread面向单核嵌入式MCU,依靠中断锁+调度锁替代自旋锁场景,没有单独spinlock组件。
atomic_t专用封装类型,提供atomic_inc/atomic_add_return等接口,硬件lock指令保证单CPU操作原子;SMP下自动多核同步,适合计数器、标记位。禁止和普通int混用。 衍生local_t:仅本地CPU原子操作,无多核同步,性能更高。
无单独原子操作组件,短变量互斥直接使用中断锁封装实现等价逻辑。
结构体struct semaphore,核心成员:atomic_t count(资源计数)、等待队列。
down()(不可中断睡眠)、down_interruptible()(可被信号唤醒)、down_trylock()(非阻塞)、up()释放。 特性:等待线程进入睡眠,释放CPU,适合长时间临界区;性能开销高于自旋锁。结构体struct rt_semaphore,16位value计数,支持FIFO/优先级等待队列。 API:rt_sem_take()/rt_sem_release(),支持超时等待。 三大使用场景:
相同:count资源计数、等待线程睡眠、支持非阻塞获取; 差异:
struct mutex,专属互斥原语,区别于二值信号量:
rt_mutex实现优先级继承,解决优先级反转;struct rt_mutex,内置original_priority、持有计数、owner指针,原生优先级继承。 核心优势:
RT-Thread无对应组件,仅Linux内核提供:
Linux完整提供三套SysV IPC:信号量、消息队列、共享内存,全局key标识,全系统进程共享:
semop,撤销机制防止进程崩溃死锁;struct rt_event,32bit标志位,每一位代表独立事件,支持逻辑与/或等待:
单条固定4字节(32位系统指针大小),容量可配置,中断可非阻塞发送,适合传递指针、简单数值。 局限:无法传输大块数据,仅传递地址句柄。
不定长消息,内存池缓存,支持紧急消息插入队首;中断可发送,仅线程阻塞接收;数据完整拷贝,无需管理外部缓冲区生命周期。
分SysV消息队列、POSIX mq,全局系统资源,多进程跨进程收发;内核消息结构复杂,支持消息类型筛选。
kmalloc(GFP_KERNEL)、信号量down()、wait事件会直接死锁。ipcrm清理。rt_sem_take永久阻塞,递归场景必须换mutex。二者均选择信号量(初始0)。
Linux专属RCU;RT-Thread读写场景无专用组件,使用mutex。
仅Linux支持SysV共享内存、套接字、管道。
Linux内核面向通用多进程SMP平台,同步机制分层丰富:底层原子、自旋锁;中层信号量、mutex、RCU;上层完整SysV/POSIX跨进程IPC,兼顾高性能多核并发与多进程隔离。 RT-Thread面向单核嵌入式实时MCU,简化锁体系,舍弃复杂多核RCU、SysV IPC,新增事件、邮箱、消息队列轻量化线程通信组件,原生内置优先级继承互斥量,更适配硬实时嵌入式场景。
二者同步底层核心逻辑完全统一:通过锁实现临界区互斥、睡眠原语解决线程等待;差异全部来源于硬件架构(多核Linux vs 单核RTOS)、业务模型(多进程PC/服务器 vs 单进程多线程嵌入式)。
实际开发选型核心原则:最短临界区、最轻量锁、避免优先级反转、禁止上下文错用锁原语,规避很大部分诡异bug。
“谢谢你看到这里”这里是女程序员的笔记本
15年+嵌入式软件工程师兼二胎宝妈
分享读书心得、工作经验,自我成长和生活方式。
希望我的文字能对你有所帮助