H HRTOS 示例
Synchronization Core

信号量机制

信号量用于任务同步与资源管理,通过计数机制控制并发访问, 实现阻塞、唤醒与调度协作。信号量是 RTOS 并发控制的基础机制之一。

示例目标

系统运行生产者任务与消费者任务,通过信号量实现任务间同步。 生产者释放资源,消费者等待并获取资源,验证信号量的阻塞与唤醒机制。

核心API os_sem_init/wait/post
同步方式 资源计数 + 阻塞队列
状态转换 Running → Blocked
唤醒机制 调度联动恢复

核心机制

  • 资源计数管理
  • 任务阻塞等待
  • 唤醒调度联动
  • 并发访问控制
Principle

原理说明

信号量是 RTOS 任务同步的核心机制

信号量(Semaphore)是一种用于任务同步和资源管理的同步原语。 通过计数机制控制对共享资源的并发访问,当资源不足时任务会阻塞等待, 当资源释放时会唤醒等待的任务,实现任务间的协作与调度联动。

机制定义: Semaphore = 资源计数 + 阻塞队列 + 唤醒机制 + 调度联动

资源计数

信号量维护一个计数器,表示可用资源的数量。 初始化时设置初始值,wait 操作减少计数,post 操作增加计数。

阻塞队列

当计数为 0 时,申请资源的任务会被放入阻塞队列等待。 阻塞队列维护所有等待该信号量的任务状态。

唤醒机制

当资源释放(post)时,信号量会从阻塞队列中选择一个任务唤醒。 被唤醒的任务重新进入就绪队列,等待调度器执行。

调度联动

信号量的阻塞和唤醒操作会触发任务调度。 任务阻塞时调度器选择其他就绪任务执行,唤醒时可能触发优先级调度。

系统关系模型: Task → Semaphore → Scheduler → Task
HRTOS Implementation

HRTOS 实现机制

HRTOS 如何实现信号量同步

在 HRTOS 中,信号量的实现围绕资源计数、阻塞队列、唤醒机制和调度联动四个核心环节展开。 每个环节都经过精心设计,确保同步机制的高效性和可靠性。

申请资源(os_sem_wait)

检查计数:计数 > 0 则获取成功,计数减 1

阻塞等待:计数 = 0 时任务进入阻塞队列

状态转换:任务从 Running 状态进入 Blocked 状态

调度触发:阻塞时触发调度器选择其他任务

任务阻塞

队列管理:任务加入信号量的等待队列

状态保存:保存任务上下文到任务栈

超时支持:支持带超时的等待操作

优先级维护:阻塞队列按优先级排序

释放资源(os_sem_post)

计数增加:信号量计数加 1

唤醒检查:检查是否有等待任务

任务唤醒:从等待队列中选择任务唤醒

调度触发:唤醒时可能触发任务调度

任务恢复

状态转换:任务从 Blocked 状态进入 Ready 状态

就绪队列:任务加入就绪队列等待调度

优先级调度:根据任务优先级决定执行顺序

上下文恢复:调度器选择时恢复任务执行

Workflow

工作流程

信号量从初始化到任务同步的完整执行路径

1初始化信号量:hrtos_main 中调用 os_sem_init 设置初始资源数量
2任务创建:创建生产者任务和消费者任务,进入 Ready 状态
3生产者运行:生产者任务执行 os_sem_post 释放资源
4消费者等待:消费者任务调用 os_sem_wait 等待资源
5阻塞与唤醒:资源不足时阻塞,资源释放时唤醒等待任务
hrtos_main → os_sem_init → os_task_create → 生产者运行 → os_sem_post → 消费者等待 → os_sem_wait → 阻塞/唤醒 → 任务恢复 → 调度执行
Core Code

核心代码

信号量同步的完整实现

生产者与消费者任务

task_A 生产者任务和 task_B 消费者任务,通过信号量实现同步

#include "hrtos.h"

#define SEM_ID 0

sbit LED_PRODUCER = P1^0;
sbit LED_CONSUMER = P1^1;
sbit LED_SEM      = P1^2;   // semaphore state indicator

/* 生产者任务 */
void task_A(void)
{
    while(1)
    {
        os_delay(2);

        os_sem_post(SEM_ID);

        LED_PRODUCER = ~LED_PRODUCER;  // 生产节奏闪烁

        LED_SEM = 1;   // 表示资源"被释放/可用"
    }
}

/* 消费者任务 */
void task_B(void)
{
    while(1)
    {
        /* 等待资源 */
        if(os_sem_wait(SEM_ID))
        {
            /* 获取资源成功 */
            LED_CONSUMER = ~LED_CONSUMER;  // 消费节奏

            LED_SEM = 0;   // 表示资源被消耗

            /* 模拟处理 */
            os_delay(1);
        }

        os_delay(1);
    }
}

系统初始化与任务创建

hrtos_main 函数,初始化信号量并创建生产者和消费者任务

/* 系统入口 */
void hrtos_main(void)
{
    LED_PRODUCER = 0;
    LED_CONSUMER = 0;
    LED_SEM = 0;

    os_sem_init(SEM_ID, 0);

    os_task_create((unsigned int)task_A, 1, 3, 5);
    os_task_create((unsigned int)task_B, 2, 2, 5);
}
Expected Result

运行结果

示例执行后的预期行为

LED 状态 LED_PRODUCER 和 LED_CONSUMER 按生产消费节奏交替变化,LED_SEM 指示资源状态
任务同步 生产者释放资源后,消费者才能获取资源,实现任务间同步
阻塞唤醒 资源不足时消费者阻塞,资源释放后消费者被唤醒并恢复执行
系统本质: 本示例的核心不是 LED,而是验证 HRTOS 中信号量的阻塞与唤醒机制,实现任务间的同步协作。
Important Notes

注意事项

使用本示例时需要关注的关键点

信号量与互斥锁的区别

信号量用于任务同步和资源计数,可以跨多个任务使用;互斥锁用于保护共享资源, 具有优先级继承机制,主要用于互斥访问。本示例展示的是信号量的同步功能。

初始计数值设置

本示例中信号量初始值为 0,表示初始无资源,消费者需要等待生产者释放资源。 如果初始值 > 0,则表示初始有可用资源,消费者可以直接获取。

任务优先级设置

生产者任务优先级为 3,消费者任务优先级为 2。 优先级设置影响任务调度顺序,需要根据实际应用场景合理配置。

阻塞队列管理

当多个任务等待同一个信号量时,阻塞队列按任务优先级排序。 资源释放时,优先唤醒高优先级的等待任务,确保系统的实时性。