Nucleus SE信号量:概览、配置与API要点
查看RTOS Revealed系列
信号量是嵌入式系统中同步共享资源访问的基础机制。它们允许任务安全获取和释放资源控制权,避免冲突。
使用信号量
在Nucleus SE中,信号量支持在构建过程中启用。单个应用最多可配置16个信号量。若不使用任何信号量,相关数据结构和API代码从最终二进制中排除,减小占用。
信号量本质是受保护的8位计数器,多任务可安全操作。任务调用Obtain递减计数器,调用Release递增。若任务尝试获取计数器为零的信号量,结果取决于API选项和系统配置:调用可能返回错误或挂起任务直至信号量可用。
配置信号量
信号量数量
信号量通过nuse_config.h中#define语句定义。关键宏NUSE_SEMAPHORE_NUMBER指定应用将使用的信号量槽位数。默认值0表示无信号量支持。有效值0到16。无效值触发nuse_config_check.h产生的编译时#error(通过nuse_config.c包含)。
将NUSE_SEMAPHORE_NUMBER设为非零值激活信号量子系统:数据结构相应定尺寸,API启用符号被处理。
API启用
每个Nucleus SE API调用由nuse_config.h中专用启用宏保护。信号量相关符号:
NUSE_SEMAPHORE_OBTAINNUSE_SEMAPHORE_RELEASENUSE_SEMAPHORE_RESETNUSE_SEMAPHORE_INFORMATIONNUSE_SEMAPHORE_COUNT
默认全设为FALSE,禁用对应服务调用并从构建中排除实现。启用特定API,将其宏设为TRUE。
以下是默认nuse_config.h文件片段:
#define NUSE_SEMAPHORE_NUMBER 0 /* 系统信号量数量 – 0‑16 */ #define NUSE_SEMAPHORE_OBTAIN FALSE /* 服务调用启用器 */ #define NUSE_SEMAPHORE_RELEASE FALSE /* 服务调用启用器 */ #define NUSE_SEMAPHORE_RESET FALSE /* 服务调用启用器 */ #define NUSE_SEMAPHORE_INFORMATION FALSE /* 服务调用启用器 */ #define NUSE_SEMAPHORE_COUNT FALSE /* 服务调用启用器 */
未配置信号量时启用API调用(除NUSE_Semaphore_Count()始终可用外)导致编译时错误。调用未启用的API因实现被省略导致链接时错误。
信号量服务调用
Nucleus SE提供八个信号量相关服务调用。前五个完全实现;其余三个为未来扩展占位。
- 获取 –
NUSE_Semaphore_Obtain() - 释放 –
NUSE_Semaphore_Release() - 重置 –
NUSE_Semaphore_Reset() - 信息 –
NUSE_Semaphore_Information() - 计数 –
NUSE_Semaphore_Count() - 创建 – Nucleus SE未实现
- 删除 – Nucleus SE未实现
- 列出所有 – Nucleus SE未实现
获取与释放操作
核心信号量操作是获取(递减)和释放(递增)。Nucleus RTOS提供灵活获取API支持可选挂起和超时。Nucleus SE镜像此行为,但任务挂起可选、不支持超时。
Nucleus RTOS获取API
原型:
STATUS NU_Obtain_Semaphore(NU_SEMAPHORE *semaphore, UNSIGNED suspend);
参数:
semaphore– 信号量控制块指针。
suspend– 可为NU_NO_SUSPEND、NU_SUSPEND或超时值。
返回值:
NU_SUCCESS– 操作成功。
NU_UNAVAILABLE– 信号量值为零。
NU_INVALID_SEMAPHORE– 无效信号量指针。
NU_INVALID_SUSPEND– 非任务上下文尝试挂起。
NU_SEMAPHORE_WAS_RESET– 任务挂起期间信号量被重置。
Nucleus SE获取API
原型:
STATUS NUSE_Semaphore_Obtain(NUSE_SEMAPHORE semaphore, U8 suspend);
参数:
semaphore– 信号量索引。
suspend– 可为NUSE_NO_SUSPEND或NUSE_SUSPEND。
返回值:
NUSE_SUCCESS– 操作成功。
NUSE_UNAVAILABLE– 信号量值为零。
NUSE_INVALID_SEMAPHORE– 无效信号量索引。
NUSE_INVALID_SUSPEND– 非任务上下文或阻塞API禁用时尝试挂起。
NUSE_SEMAPHORE_WAS_RESET– 挂起期间信号量重置。
实现亮点
禁用阻塞时,实现仅检查计数器非零则递减并返回NUSE_SUCCESS;为零返回NUSE_UNAVAILABLE。
if (NUSE_Semaphore_Counter[semaphore] != 0) { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; } else { return_value = NUSE_UNAVAILABLE; } 启用阻塞时,例程进入do…while循环尝试获取。计数器为零且suspend为NUSE_SUSPEND时阻塞任务。释放时,首个等待任务被唤醒并重试获取。 do { if (NUSE_Semaphore_Counter[semaphore] != 0) { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; } else { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_UNAVAILABLE; } else { NUSE_Semaphore_Blocking_Count[semaphore]++; NUSE_Suspend_Task(NUSE_Task_Active, semaphore << 4 | NUSE_SEMAPHORE_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } } while (suspend == NUSE_SUSPEND); Nucleus RTOS释放API
原型:
STATUS NU_Release_Semaphore(NU_SEMAPHORE *semaphore);
参数:
semaphore– 信号量控制块指针。
返回值:
NU_SUCCESS– 操作成功。
NU_INVALID_SEMAPHORE– 无效信号量指针。
Nucleus SE释放API
原型:
STATUS NUSE_Semaphore_Release(NUSE_SEMAPHORE semaphore);
参数:
semaphore– 信号量索引。
返回值:
NUSE_SUCCESS– 操作成功。
NUSE_INVALID_SEMAPHORE– 无效信号量索引。
NUSE_UNAVAILABLE– 计数器已达255;无法递增。
实现亮点
释放例程先检查计数器低于最大值(255)。若是,递增计数器。启用阻塞且有任务等待该信号量时,唤醒首个等待任务。
NUSE_CS_Enter(); if (NUSE_Semaphore_Counter[semaphore] < 255) { NUSE_Semaphore_Counter[semaphore]++; return_value = NUSE_SUCCESS; #if NUSE_BLOCKING_ENABLE if (NUSE_Semaphore_Blocking_Count[semaphore] != 0) { NUSE_Semaphore_Blocking_Count[semaphore]--; for (U8 index = 0; index < NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_SEMAPHORE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == semaphore)) { NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS; NUSE_Wake_Task(index); break; } } } #endif } else { return_value = NUSE_UNAVAILABLE; } NUSE_CS_Exit(); return return_value; 当任务挂起于信号量,释放它会唤醒首个等待任务,使其继续执行。
下一篇将探讨事件标志组及其相关数据结构。
Colin Walls在电子行业拥有三十多年经验,主要专注嵌入式软件。频繁在会议演讲、撰写技术文章,著有两本嵌入式软件书籍。Colin是Mentor Embedded(门托图形嵌入式软件部)嵌入式软件技术专家,驻英国。博客https://blogs.mentor.com/colinwalls。邮件colin_walls@mentor.com联系。
嵌入式