任务同步与通信
2026/7/16大约 7 分钟内核组件内核同步通信IPC
任务同步与通信
📚 本节导读
学习时长: 约 90 分钟
难度级别: ⭐⭐⭐⭐☆
前置知识: 任务管理、中断管理、C 语言基础
在多任务实时操作系统中,任务之间需要协调对共享资源的访问,也需要在任务之间传递数据。OneOS 提供了丰富且完整的 IPC(Inter-Process Communication,进程间通信) 机制,涵盖同步原语和通信机制两大类。
本节是对 OneOS 所有 IPC 机制的全景概述,帮助你在实际开发中快速选择合适的机制。
🎯 学习目标
- 理解 OneOS 中各类 IPC 机制的分类和适用场景
- 掌握信号量、互斥锁、事件、消息队列、邮箱、自旋锁、工作队列的核心区别
- 能够根据实际需求选择合适的同步或通信机制
- 理解 PRIO 与 FIFO 唤醒策略的含义
- 了解静态创建与动态创建两种模式的区别
一、IPC 机制全景
OneOS 提供了七种 IPC 机制,按功能可分为两大类:
┌─────────────────────────────────────────────────────────────────────┐
│ OneOS IPC 机制全景 │
├──────────────────────────┬──────────────────────────────────────────┤
│ 同步机制 (Synchronization) │ 通信机制 (Communication) │
├──────────────────────────┼──────────────────────────────────────────┤
│ • 信号量 (Semaphore) │ • 事件 (Event) │
│ • 互斥锁 (Mutex) │ • 消息队列 (Message Queue) │
│ • 自旋锁 (Spinlock) │ • 邮箱 (Mailbox) │
│ │ │
│ 延迟执行 (Deferred Work) │ │
│ • 工作队列 (Workqueue) │ │
└──────────────────────────┴──────────────────────────────────────────┘二、核心机制对比
下表从多个维度对比了 OneOS 的全部 IPC 机制:
| 特性 | 信号量 | 互斥锁 | 事件 | 消息队列 | 邮箱 | 自旋锁 | 工作队列 |
|---|---|---|---|---|---|---|---|
| 用途 | 资源计数 / 同步 | 互斥访问共享资源 | 多条件同步 | 变长数据传递 | 指针值传递 | SMP 临界区保护 | 延迟工作执行 |
| 数据传递 | 无 | 无 | 32 位标志 | 数据副本(变长) | 指针值(固定大小) | 无 | 函数 + 参数 |
| 阻塞等待 | 是 | 是 | 是 | 是 | 是 | 否(忙等) | 否(异步) |
| 优先级继承 | 否 | 是 | 否 | 否 | 否 | 否 | 否 |
| 递归持有 | 否 | 支持 | 否 | 否 | 否 | 否 | 否 |
| 中断可用 | 仅 post | 否 | 仅 send | 否 | 否 | 是 | 否 |
| SMP 安全 | 内部保护 | 内部保护 | 内部保护 | 内部保护 | 内部保护 | 是 | 内部保护 |
| 一幅多收 | 否 | 否 | 是 | 是(一条消息一份) | 是(一条邮件一份) | 否 | 否 |
| P操作 | os_semaphore_wait | os_mutex_lock | os_event_recv | os_msgqueue_recv | os_mailbox_recv | os_spin_lock | os_work_run |
| V操作 | os_semaphore_post | os_mutex_unlock | os_event_send | os_msgqueue_send | os_mailbox_send | os_spin_unlock | — |
三、选型指南
3.1 何时使用信号量
- 资源计数:管理有限个数的资源(如缓冲区槽位、外设通道)
- 任务同步:一个任务等待另一个任务完成某个操作(二进制信号量)
- 中断与任务同步:中断中释放信号量,任务中等待信号量
3.2 何时使用互斥锁
- 共享资源互斥访问:保护全局变量、外设寄存器、数据结构等关键区域
- 需要优先级继承:防止优先级反转问题
- 需要递归锁:同一任务可以多次加锁
3.3 何时使用事件
- 多条件触发:一个任务等待多个事件条件中的任意一个(OR)或全部(AND)
- 一对多 / 多对多同步:一个事件源可以同时唤醒多个等待任务
- 状态标志传递:用 32 个位标记不同的系统状态
3.4 何时使用消息队列
- 变长数据传输:任务之间需要传递不同大小的数据块
- 数据缓冲:生产者-消费者模式,数据需要排队处理
- 数据拷贝:需要发送方和接收方各自持有独立数据副本
3.5 何时使用邮箱
- 指针值传递:传递内存地址、句柄或整数值,不需要拷贝数据本身
- 轻量通信:每次传递固定大小的值(
os_ubase_t),效率更高 - 固定容量缓冲:快速传递固定数量的消息
3.6 何时使用自旋锁
- SMP 多核保护:多核场景下保护极短的临界区
- 中断上下文:在中断中加锁(互斥锁不能在中断中使用)
- 极短临界区:临界区代码执行时间极短(微秒级),忙等开销小于上下文切换开销
3.7 何时使用工作队列
- 延迟执行:将工作推迟到工作线程中执行,释放当前上下文
- Bottom-Half 处理:中断上半部只做关键操作,将耗时操作交给工作队列
- 异步操作:不需要等待结果的操作,丢给工作队列即可
四、唤醒策略:PRIO vs FIFO
OneOS 的同步对象在释放时,如果有多个任务正在等待,需要决定唤醒哪个任务。每种机制都支持两种唤醒策略:
| 策略 | 宏定义值 | 含义 |
|---|---|---|
| PRIO(优先级) | 0x55 | 唤醒等待队列中优先级最高的任务。这是默认策略 |
| FIFO(先进先出) | 0xAA | 唤醒等待队列中等待时间最长的任务 |
设置唤醒策略的 API:
os_semaphore_set_wake_type(sem_id, OS_SEM_WAKE_TYPE_PRIO);
os_mutex_set_wake_type(mutex_id, OS_MUTEX_WAKE_TYPE_FIFO);
os_event_set_wake_type(event_id, OS_EVENT_WAKE_TYPE_PRIO);
os_msgqueue_set_wake_type(mq_id, OS_MQ_WAKE_TYPE_PRIO);
os_mailbox_set_wake_type(mb_id, OS_MB_WAKE_TYPE_PRIO);注意:自旋锁和工作队列不涉及等待任务队列,因此没有唤醒策略的概念。
五、静态创建与动态创建
OneOS 支持两种对象创建方式:
┌──────────────────────────────────────────────────────────────────────┐
│ 两种创建方式对比 │
├──────────────────────┬───────────────────────────────────────────────┤
│ 动态创建 (Dynamic) │ 静态创建 (Static) │
├──────────────────────┼───────────────────────────────────────────────┤
│ 运行时从堆分配内存 │ 编译时确定内存,使用全局变量 │
│ 需要启用 OS_USING_HEAP│ 不需要堆支持 │
│ 灵活,可动态创建/销毁 │ 确定性高,无内存碎片风险 │
│ 适合资源动态变化场景 │ 适合资源受限、确定性要求高的场景 │
└──────────────────────┴───────────────────────────────────────────────┘静态定义宏:
| 机制 | 静态定义宏 | 静态创建函数 |
|---|---|---|
| 信号量 | OS_SEMAPHORE_DEFINE(name) | os_semaphore_create(&cb, ...) |
| 互斥锁 | OS_MUTEX_DEFINE(name) | os_mutex_create(&cb, ...) |
| 事件 | OS_EVENT_DEFINE(name) | os_event_create(&cb, ...) |
| 消息队列 | OS_MSGQUEUE_DEFINE(name) + OS_MSGQUEUE_POOL_DEFINE(name, count, size) | os_msgqueue_create_static(&cb, ...) |
| 邮箱 | OS_MAILBOX_DEFINE(name) + OS_MAILBOX_POOL_DEFINE(name, count) | os_mailbox_create_static(&cb, ...) |
| 自旋锁 | OS_DEFINE_SPINLOCK(var) | os_spin_lock_init(&lock) |
| 工作队列 | OS_WORKQUEUE_DEFINE(name) | os_workqueue_create(&cb, ...) |
| 工作项 | OS_WORK_DEFINE(name) | os_work_init(&work, ...) |
六、子章节导航
| 章节 | 标题 | 核心内容 |
|---|---|---|
| 4.3.1 | 信号量 | 计数信号量、二值信号量、资源管理 |
| 4.3.2 | 互斥锁 | 互斥访问、优先级继承、递归锁 |
| 4.3.3 | 事件 | 32 位事件标志、AND/OR 触发 |
| 4.3.4 | 消息队列 | 变长数据传输、紧急发送 |
| 4.3.5 | 邮箱 | 指针值传递、轻量级通信 |
| 4.3.6 | 自旋锁 | SMP 临界区保护、中断安全 |
| 4.3.7 | 工作队列 | 延迟工作执行、Bottom-Half |
📝 本节小结
OneOS 提供了七种 IPC 机制,覆盖了嵌入式实时操作系统中常见的同步与通信需求:
- 同步:信号量(资源计数)、互斥锁(互斥保护)、自旋锁(SMP 临界区)
- 通信:事件(标志位)、消息队列(变长数据)、邮箱(指针值)
- 延迟执行:工作队列(异步延迟工作)
选择时的核心原则:
- 保护共享资源 → 互斥锁(需要优先级继承)或自旋锁(极短临界区 / 中断上下文)
- 资源计数 → 信号量
- 多条件同步 → 事件
- 传递数据 → 消息队列(变长数据)或邮箱(指针值)
- 延迟执行 → 工作队列