uC/OS-III之资源管理--互斥型信号量
来源:互联网 发布:复杂网络应用实例 编辑:程序博客网 时间:2024/06/04 19:21
1.uC/OS-III支持一种特殊的二进制信号量–互斥型信号量。
2.互斥型信号量通过安全优先级继承机制(一旦一个具有高优先级的任务H想要访问共享资源,占有该资源的任务的优先级将被提升至与任务H一样),来避免无界优先级翻转的问题。
3.互斥型信号量是一种被定义为OS_MUTEX数据类型的内核对象,它的定义位于os.h中。
注:与信号量一样,只有任务才能使用互斥型信号量(中断服务程序不可以)。
typedef struct os_mutex OS_MUTEX; // 625行struct os_mutex { // 817行 - 830行 OS_OBJ_TYPE Type; // 互斥信号量的类型,必须设置成OS_OBJ_TYPE_MUTEX CPU_CHAR *NamePtr; // 互斥信号量的名称 OS_PEND_LIST PendList; // 任务挂起表#if OS_CFG_DBG_EN > 0u // 调试相关 OS_MUTEX *DbgPrevPtr; OS_MUTEX *DbgNextPtr; CPU_CHAR *DbgNamePtr;#endif OS_TCB *OwnerTCBPtr; // 指向占有该互斥信号量的任务的任务控制块OS_TCB OS_PRIO OwnerOriginalPrio; // 记录任务占有互斥信号量之前的优先级 OS_NESTING_CTR OwnerNestingCtr; // 互斥信号量的嵌套深度 CPU_TS TS; // 记录上一次被释放的时间};
4.互斥型信号量通过OSMutexCreate()创建,它的定义位于os_mutex.c中。
void OSMutexCreate (OS_MUTEX *p_mutex, CPU_CHAR *p_name, OS_ERR *p_err) // 66行 - 118行{ CPU_SR_ALLOC(); // 声明变量cpu_sr,用来临时存储CPU的状态寄存器#ifdef OS_SAFETY_CRITICAL // 系统安全性检查 if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; }#endif#ifdef OS_SAFETY_CRITICAL_IEC61508 // 系统安全性检查(IEC61508) if (OSSafetyCriticalStartFlag == DEF_TRUE) { *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME; return; }#endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u // 允许进行ISR调用检查 if (OSIntNestingCtr > (OS_NESTING_CTR)0) { // 不允许在ISR中调用 *p_err = OS_ERR_CREATE_ISR; return; }#endif#if OS_CFG_ARG_CHK_EN > 0u // 允许参数检查 if (p_mutex == (OS_MUTEX *)0) { // 无效参数 *p_err = OS_ERR_OBJ_PTR_NULL; return; }#endif CPU_CRITICAL_ENTER(); // 进入临界区 p_mutex->Type = OS_OBJ_TYPE_MUTEX; // 标记结构体为互斥型信号量 p_mutex->NamePtr = p_name; p_mutex->OwnerTCBPtr = (OS_TCB *)0; p_mutex->OwnerNestingCtr = (OS_NESTING_CTR)0; // 当OwnerNestingCtr为0时,互斥信号量可用 p_mutex->TS = (CPU_TS )0; p_mutex->OwnerOriginalPrio = OS_CFG_PRIO_MAX; OS_PendListInit(&p_mutex->PendList); // 初始化挂起表#if OS_CFG_DBG_EN > 0u OS_MutexDbgListAdd(p_mutex);#endif OSMutexQty++; // 系统互斥信号量数目加1 CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_NONE;}
5.等待互斥信号量使用OSMutexPend(),它的定义位于os_mutex.c中。
void OSMutexPend (OS_MUTEX *p_mutex, OS_TICK timeout, OS_OPT opt, CPU_TS *p_ts, OS_ERR *p_err) // 329行 - 493行{ OS_PEND_DATA pend_data; OS_TCB *p_tcb; CPU_SR_ALLOC(); // 声明变量cpu_sr,用来临时存储CPU的状态寄存器#ifdef OS_SAFETY_CRITICAL // 系统安全性检查 if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; }#endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u // 允许进行ISR调用检查 if (OSIntNestingCtr > (OS_NESTING_CTR)0) { // 不允许在ISR中调用该函数 *p_err = OS_ERR_PEND_ISR; return; }#endif#if OS_CFG_ARG_CHK_EN > 0u // 允许进行参数检查 if (p_mutex == (OS_MUTEX *)0) { // 无效的参数 *p_err = OS_ERR_OBJ_PTR_NULL; return; } switch (opt) { case OS_OPT_PEND_BLOCKING: case OS_OPT_PEND_NON_BLOCKING: break; default: // 无效的选项 *p_err = OS_ERR_OPT_INVALID; return; }#endif#if OS_CFG_OBJ_TYPE_CHK_EN > 0u // 允许进行类型检查 if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) { // 确保互斥型已被创建 *p_err = OS_ERR_OBJ_TYPE; return; }#endif if (p_ts != (CPU_TS *)0) { *p_ts = (CPU_TS )0; // 初始化返回的时间戳参数 } CPU_CRITICAL_ENTER(); // 进入临界区 if (p_mutex->OwnerNestingCtr == (OS_NESTING_CTR)0) { // 嵌套层数OwnerNestingCtr为0时,表示互斥信号量可用 p_mutex->OwnerTCBPtr = OSTCBCurPtr; p_mutex->OwnerOriginalPrio = OSTCBCurPtr->Prio; p_mutex->OwnerNestingCtr = (OS_NESTING_CTR)1; if (p_ts != (CPU_TS *)0) { *p_ts = p_mutex->TS; // 返回上次释放互斥信号量的时间 } CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_NONE; return; } // 互斥信号量不可用 if (OSTCBCurPtr == p_mutex->OwnerTCBPtr) { // 当前任务正在使用互斥信号量 p_mutex->OwnerNestingCtr++; // 嵌套层数加1 if (p_ts != (CPU_TS *)0) { *p_ts = p_mutex->TS; } CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_MUTEX_OWNER; // 说明一下当前任务已拥有该互斥信号量 return; } if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { // 非阻塞型 CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_PEND_WOULD_BLOCK; return; } else { // 阻塞型 if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { // 调度器是锁定 CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_SCHED_LOCKED; return; } } // 阻塞型 OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); // 进入临界区,使能中断 p_tcb = p_mutex->OwnerTCBPtr; // 执行占有该互斥信号量的任务的任务控制块OS_TCB if (p_tcb->Prio > OSTCBCurPtr->Prio) { // 拥有互斥信号量的任务的优先级低于当前任务的优先级 switch (p_tcb->TaskState) { case OS_TASK_STATE_RDY: OS_RdyListRemove(p_tcb); // 把当前任务从就绪表中删除 p_tcb->Prio = OSTCBCurPtr->Prio; // 提升拥有互斥信号量的任务的优先级 OS_PrioInsert(p_tcb->Prio); // 更新优先级位映射表 OS_RdyListInsertHead(p_tcb); // 插入到任务就绪表中 break; case OS_TASK_STATE_DLY: case OS_TASK_STATE_DLY_SUSPENDED: case OS_TASK_STATE_SUSPENDED: p_tcb->Prio = OSTCBCurPtr->Prio; // 仅仅提高拥有互斥信号量的任务的优先级 break; case OS_TASK_STATE_PEND: // 改变在挂起表中的位置 case OS_TASK_STATE_PEND_TIMEOUT: case OS_TASK_STATE_PEND_SUSPENDED: case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: OS_PendListChangePrio(p_tcb, OSTCBCurPtr->Prio); // 改变挂起表中的优先级 break; default: OS_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_STATE_INVALID; return; } } OS_Pend(&pend_data, // ??? (OS_PEND_OBJ *)((void *)p_mutex), OS_TASK_PEND_ON_MUTEX, timeout); OS_CRITICAL_EXIT_NO_SCHED(); // 退出临界区,不调度 OSSched(); // 执行调度程序 CPU_CRITICAL_ENTER(); // 进入临界区 switch (OSTCBCurPtr->PendStatus) { case OS_STATUS_PEND_OK: // 得到互斥信号量 if (p_ts != (CPU_TS *)0) { *p_ts = OSTCBCurPtr->TS; } *p_err = OS_ERR_NONE; break; case OS_STATUS_PEND_ABORT: // 等待被禁止 if (p_ts != (CPU_TS *)0) { *p_ts = OSTCBCurPtr->TS; } *p_err = OS_ERR_PEND_ABORT; break; case OS_STATUS_PEND_TIMEOUT: // 等待超时 if (p_ts != (CPU_TS *)0) { *p_ts = (CPU_TS )0; } *p_err = OS_ERR_TIMEOUT; break; case OS_STATUS_PEND_DEL: // 互斥信号量被删除 if (p_ts != (CPU_TS *)0) { *p_ts = OSTCBCurPtr->TS; } *p_err = OS_ERR_OBJ_DEL; break; default: *p_err = OS_ERR_STATUS_INVALID; break; } CPU_CRITICAL_EXIT(); // 退出临界区}
6.任务释放互斥型信号量使用OSMutexPost(),它的定义位于os_mutex.c中。
void OSMutexPost (OS_MUTEX *p_mutex, OS_OPT opt, OS_ERR *p_err) // 636行 - 727行{ OS_PEND_LIST *p_pend_list; OS_TCB *p_tcb; CPU_TS ts; CPU_SR_ALLOC(); // 声明变量cpu_sr,用来临时保存CPU的状态寄存器#ifdef OS_SAFETY_CRITICAL // 允许进行系统安全性检查 if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; }#endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u // 允许进行ISR调用检查 if (OSIntNestingCtr > (OS_NESTING_CTR)0) { // 不允许在ISR中调用该函数 *p_err = OS_ERR_POST_ISR; return; }#endif#if OS_CFG_ARG_CHK_EN > 0u // 允许进行参数检查 if (p_mutex == (OS_MUTEX *)0) { // 无效参数 *p_err = OS_ERR_OBJ_PTR_NULL; return; }#endif#if OS_CFG_OBJ_TYPE_CHK_EN > 0u // 允许进行目标类型检查 if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) { // 该对象不是互斥型信号量 *p_err = OS_ERR_OBJ_TYPE; return; }#endif CPU_CRITICAL_ENTER(); // 进入临界区 if (OSTCBCurPtr != p_mutex->OwnerTCBPtr) { // 当前任务不是拥有该互斥型信号量的任务 CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_MUTEX_NOT_OWNER; return; } OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); // 进入临界区,使能中断 ts = OS_TS_GET(); // 获取时间戳 p_mutex->TS = ts; p_mutex->OwnerNestingCtr--; // 减少互斥信号量的嵌套层数 if (p_mutex->OwnerNestingCtr > (OS_NESTING_CTR)0) { // 嵌套层数不为0,表示操作未完成 OS_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_MUTEX_NESTING; return; } p_pend_list = &p_mutex->PendList; // 获取挂起表 if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0) { // 挂起表为空(没有任务等待该互斥信号量) p_mutex->OwnerTCBPtr = (OS_TCB *)0; p_mutex->OwnerNestingCtr = (OS_NESTING_CTR)0; OS_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_NONE; return; } // 挂起表不为空 if (OSTCBCurPtr->Prio != p_mutex->OwnerOriginalPrio) { // 任务的当前优先级与它之前的优先级不同 OS_RdyListRemove(OSTCBCurPtr); // 把当前任务从就绪表中删除 OSTCBCurPtr->Prio = p_mutex->OwnerOriginalPrio; // 恢复其之前的优先级 OS_PrioInsert(OSTCBCurPtr->Prio); // 更新优先级位映射表 OS_RdyListInsertTail(OSTCBCurPtr); // 插入到就绪表中的尾部 OSPrioCur = OSTCBCurPtr->Prio; } // 获取挂起表中的头部的OS_TCB p_tcb = p_pend_list->HeadPtr->TCBPtr; p_mutex->OwnerTCBPtr = p_tcb; // 给互斥型信号量一个新的拥有者 p_mutex->OwnerOriginalPrio = p_tcb->Prio; p_mutex->OwnerNestingCtr = (OS_NESTING_CTR)1; OS_Post((OS_PEND_OBJ *)((void *)p_mutex), // 发送互斥型信号量 (OS_TCB *)p_tcb, (void *)0, (OS_MSG_SIZE )0, (CPU_TS )ts); OS_CRITICAL_EXIT_NO_SCHED(); // 退出临界区,不调度 if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) { OSSched(); // 执行调度程序 } *p_err = OS_ERR_NONE;}
阅读全文
0 0
- uC/OS-III之资源管理--互斥型信号量
- uC/OS-III之资源管理
- uC/OS-III之信号量
- uC/OS-III之任务信号量
- uc/os-iii学习笔记-资源管理(中断、信号、信号量、互斥信号量)
- uC/OS之信号量
- uc/os-ii互斥型信号量
- uC/OS-III之系统内部任务
- uC/OS-III之任务调度总结
- uC/OS-III之中断管理总结
- uC/OS-III之学习总结
- uC/OS-III之时钟节拍列表
- uC/OS-III之时间管理
- uC/OS-III之定时器管理
- uC/OS-III之任务挂起表
- uC/OS-III之任务同步
- uC/OS-III之事件标志组
- uC/OS-III之消息传递
- 刷题--树的子结构
- Windows 窗口层次关系(转)
- copy和mutable copy
- 最长递增子序列的思索
- 线段树入门
- uC/OS-III之资源管理--互斥型信号量
- “共享经济”的风催熟了“信用经济”
- C++对象构造函数失败会直接回收已分配的内存
- B. Sagheer, the Hausmeister(codeforce 417 div2 B, dfs)
- 自定义配置 mpv 播放器
- 记录一些常用的utils方法6
- 【tensorflow学习】BasicLSTMCell 源码分析
- xv6 lazy page allocation
- AM2320 温湿度计 单总线读取数据