概述
信号量是多任务系统中实现任务间同步,并且协调多任务对共享资源访问的一种互斥机制。信号量允许有多个使用者,所以采用计数值来表示可用的资源数,当请求一个信号量时,该计数值减1,若此时计数值大于等于0,表示当前有可用的信号量,则任务获得信号量,可以访问资源,若此时计数值为负数,则任务进入阻塞状态,释放处理器资源。当获取信号量的任务执行完操作,释放信号量时,则将当前计数值加1,如果当前存在等待该资源的任务,则任务被唤醒而获得该信号量。
超时时间
信号量获取可设置超时时间,如果任务在超时时间到期后仍未等待信号量,则任务解除阻塞进入就绪状态。
多任务同步
多个任务可以等待同一个信号量,若信号量可用或信号量被释放,通常情况下,系统会将阻塞在该信号量上优先级最高的任务置于就绪状态,提供了面向所有阻塞任务的信号量释放机制,可以将阻塞在该信号量上的所有任务都置为就绪状态。
信号量功能函数
函数名 | 描述 |
aos_sem_create() | 信号量创建函数(推荐),需指定计数值 |
aos_sem_new() | 信号量创建函数(兼容3.1),需指定计数值 |
aos_sem_free() | 信号量删除函数 |
aos_sem_wait() | 信号量获取函数,可以指定超时时间 |
aos_sem_signal() | 信号量释放函数,只唤醒阻塞在此信号量上的最高优先级任务 |
aos_sem_signal_all() | 信号量释放函数,唤醒阻塞在此信号量上的所有任务 |
aos_sem_is_valid() | 判断信号量具柄是否合法函数 |
常用配置
软件定时器功能:默认使能,如需修改,在YAML中修改RHINO_CONFIG_SEM配置
def_config:
RHINO_CONFIG_SEM: 0
API说明
使用示例
示例代码参考example/sem_example.c,该示例使用信号量实现多任务同步,具体场景为创建一个高优先级任务A,一个低优先级任务B,任务A和任务B同时等待同一信号量,此时测试任务T调用aos_sem_signal()释放信号量,任务A首先获得信号量,任务A操作完成后释放一次信号量,此时任务B获取信号量得到运行。
示例说明如下:
t0时刻,任务T调用aos_sem_create()创建一信号量,初始计数值为0。任务T然后调用aos_task_create()创建任务A和任务B,任务A优先级为30,任务B优先级为31。任务A和任务B运行后因等待信号量而阻塞。
t1时刻,任务T调用aos_sem_signal()释放信号量,任务A获得信号量。
t2时刻,任务A调用aos_sem_signal()释放信号量,任务B获得信号量。
该示例可配置到helloworld_demo中运行,相关代码的下载、编译和固件烧录均依赖AliOS Things配套的开发工具 ,所以首先需要参考《AliOS Things集成开发环境使用说明之搭建开发环境》,下载安装 。 待开发环境搭建完成后,可以按照以下步骤进行示例的测试。
步骤1 创建或打开工程
打开已有工程
如果用于测试的案例工程已存在,可参考《AliOS Things集成开发环境使用说明之打开工程》打开已有工程。
创建新的工程
组件的示例代码可以通过编译链接到AliOS Things的任意案例(solution)来运行,这里选择helloworld_demo案例。helloworld_demo案例相关的源代码下载可参考《AliOS Things集成开发环境使用说明之创建工程》。
步骤2 添加组件
案例下载完成后,需要在helloworld_demo组件的package.yaml中添加对组件的依赖:
depends:
- osal_aos: dev_aos # helloworld_demo中引入osal_aos组件
步骤3 下载组件
在已安装了的开发环境工具栏中,选择Terminal -> New Terminal启动终端,并且默认工作路径为当前工程的workspace,此时在终端命令行中输入:
aos install osal_aos
上述命令执行成功后,组件源码则被下载到了./components/osal_aos路径中。
步骤4 添加示例
在osal_aos组件的package.yaml中添加example示例代码:
depends:
- rhino: dev_aos
- cli: dev_aos # 添加cli依赖
source_file:
- "*.c"
- "example/sem_example.c" # 添加 sem_example.c
步骤5 编译固件
在示例代码已经添加至组件的配置文件,并且helloworld_demo已添加了对该组件的依赖后,就可以编译helloworld_demo案例来生成固件了,具体编译方法可参考《AliOS Things集成开发环境使用说明之编译固件》。
步骤6 烧录固件
helloworld_demo案例的固件生成后,可参考《AliOS Things集成开发环境使用说明之烧录固件》来烧录固件。
步骤7 打开串口
固件烧录完成后,可以通过串口查看示例的运行结果,打开串口的具体方法可参考《AliOS Things集成开发环境使用说明之查看日志》。
当串口终端打开成功后,可在串口中输入help来查看已添加的测试命令。
步骤8 测试示例
CLI命令行输入:
sem_example
关键日志:
[aos_sem_example][0x34035840]field1=1449208480, field2=1449208480, field3=1449208480, field4=1449208480
[aos_sem_example][0x34035d10]field1=670588782, field2=670588782, field3=670588782, field4=670588782
[aos_sem_example][0x34035840]field1=1648917010, field2=1648917010, field3=1648917010, field4=1648917010
[aos_sem_example][0x34035d10]field1=1949034929, field2=1949034929, field3=1949034929, field4=1949034929
[aos_sem_example][0x34035840]field1=672861528, field2=672861528, field3=672861528, field4=672861528
[aos_sem_example][0x34035d10]field1=820049120, field2=820049120, field3=820049120, field4=820049120
注意事项
中断禁止信号量获取检测
信号量的获取接口在中断上下文调用很容易发生死锁问题。当被打断的上下文和打断的中断上下文要获取同一个信号量时,会发生互相等待的情况。有些内核将这种判断处理交由上层软件进行判断和使用,本内核会在take信号量检测,如果是中断上下文,则直接返回失败。
占用信号量非等待、永远等待、延时使用区别
应用程序在获取信号量时,需要按照实际的需求,来安排信号量获取策略。aos_sem_take传入延时timeout为0,获取不到信号量会立即报失败;timeout为AOS_WAIT_FOREVER时,会永远在此等待,直到获取到信号量,可能会造成该任务无法继续运行;其他值标识最大延迟的时间上限,达到上限时,即使未获取到信号量,任务也会被唤醒,并返回错误。
FAQ
Q1: 调用aos_sem_task()接口无限期的等待信号量,timeout参数怎么设置? 答:将timeout赋值为AOS_WAIT_FOREVER。