uc/os-ii互斥型信号量
2015-07-03 10:06
369 查看
互斥信号量(Mutual Exclusion Semaphores)也称为Mutex,用于实现对共享资源的独占处理,互斥信号量也是一个二值信号量,利用它可以降解优先级反转问题。
当高优先级任务需要使用某个共享资源,而恰巧该共享资源又被一个低优先级任务占用时,优先级反转问题就会发生。为了降解优先级反转,内核就必须支持优先级继承,将低优先级任务的优先级提升到高于高优先级任务的优先级,直到低优先级任务处理完毕共享资源。
互斥信号量只能提供给任务使用,因为互斥信号量是用来处理共享资源的
µC/OS-Ⅱ的互斥信号量由四个元素组成:1个标志,指示Mutex是否可用(0xFF或其它);1个优先级继承优先级PIP,一旦有高优先级任务需要Mutex,内核就会将PIP赋给占用Mutex的任务;1个指向占有该Mutex的任务指针;1个Mutex等待任务列表。
µC/OS-Ⅱ提供了六种对互斥信号量进行管理的函数,函数所属文件是OS_MUTEX.C。
OSMutexCreate()函数的主要工作过程是:首先进行运行条件检查;其次检查PIP优先级是否被占用;再次检查是否有可用的事件控制块;最后当上述条件都满足后,进行Mutex的建立。此时,因为已经取走了一个空闲ECB,所以要调整空闲ECB链表指针,使其指向下一个空闲ECB。紧接着将ECB设置成Mutex类型,且保存PIP并将Mutex设置为有效状态。当等待任务列表初始化完毕后,返回ECB指针。其中,值得注意的是:这里的事件计数器 OSEventCt与信号量的不同,其高8位保存PIP,低8位在没有任务占用时为0xFF,有任务占用时,用于保存占用任务的优先级。这样做的目的是为了减少数据量,避免OS_EVENT数据结构的额外开销。
图示为OSMutexCreate()函数返回前的ECB数据结构:
OSMutexDel()函数主要工作过程是:首先进行运行条件检查,若不满足,则返回空指针和错误代码;其次按删除条件选择参数opt进行删除,删除后还需要将Mutex的ECB指针交还给空闲ECB链表;如果占有Mutex的任务被提升过优先级,还需调用
OSMutexPend()函数的主要工作过程如下:① 进行运行条件检查;② 满足运行条件后,首先检查是否有Mutex可用,如果有可用的Mutex,则占用这个Mutex,调用者获得共享资源的使用权;③ 如果没有可用的Mutex,则需要检查Mutex的占用者是否需要提升优先级;④ 对需要提升优先级的占用者进行一系列处理;⑤ 将Mutex占用者的优先级改为PIP;⑥ 挂起调用者,并调用调度函数切换任务;⑦ 当调用者再次运行时,需要检查调用者是因为超时期满还是得到Mutex而运行的,并作相应处理。
OSMutexPost()函数用于释放Mutex。当高优先级任务想得到Mutex时,如果Mutex占用者的优先级已经被升高,那么该函数使优先级升高了的任务恢复原来的优先级。如果有多个任务在等待一个Mutex,那么其中优先级最高的任务获得Mutex。此后,该函数将调用调度函数,进行任务切换。如果没有任务在等待这个Mutex,则将Mutex的值设为0xFF,表示有mutx可用。
当高优先级任务需要使用某个共享资源,而恰巧该共享资源又被一个低优先级任务占用时,优先级反转问题就会发生。为了降解优先级反转,内核就必须支持优先级继承,将低优先级任务的优先级提升到高于高优先级任务的优先级,直到低优先级任务处理完毕共享资源。
互斥信号量只能提供给任务使用,因为互斥信号量是用来处理共享资源的
µC/OS-Ⅱ的互斥信号量由四个元素组成:1个标志,指示Mutex是否可用(0xFF或其它);1个优先级继承优先级PIP,一旦有高优先级任务需要Mutex,内核就会将PIP赋给占用Mutex的任务;1个指向占有该Mutex的任务指针;1个Mutex等待任务列表。
µC/OS-Ⅱ提供了六种对互斥信号量进行管理的函数,函数所属文件是OS_MUTEX.C。
OSMutexCreate()函数的主要工作过程是:首先进行运行条件检查;其次检查PIP优先级是否被占用;再次检查是否有可用的事件控制块;最后当上述条件都满足后,进行Mutex的建立。此时,因为已经取走了一个空闲ECB,所以要调整空闲ECB链表指针,使其指向下一个空闲ECB。紧接着将ECB设置成Mutex类型,且保存PIP并将Mutex设置为有效状态。当等待任务列表初始化完毕后,返回ECB指针。其中,值得注意的是:这里的事件计数器 OSEventCt与信号量的不同,其高8位保存PIP,低8位在没有任务占用时为0xFF,有任务占用时,用于保存占用任务的优先级。这样做的目的是为了减少数据量,避免OS_EVENT数据结构的额外开销。
图示为OSMutexCreate()函数返回前的ECB数据结构:
OSMutexDel()函数主要工作过程是:首先进行运行条件检查,若不满足,则返回空指针和错误代码;其次按删除条件选择参数opt进行删除,删除后还需要将Mutex的ECB指针交还给空闲ECB链表;如果占有Mutex的任务被提升过优先级,还需调用
OSMutex_RdyAtPrio(ptcb, prio);恢复原来的优先级。
OS_EVENT *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *perr) { BOOLEAN tasks_waiting; OS_EVENT *pevent_return; INT8U pip; /* Priority inheritance priority */ INT8U prio; OS_TCB *ptcb; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0; #endif #if OS_ARG_CHK_EN > 0 if (perr == (INT8U *)0) { /* Validate 'perr' */ return (pevent); } if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ *perr = OS_ERR_PEVENT_NULL; return (pevent); } #endif if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */ *perr = OS_ERR_EVENT_TYPE; return (pevent); } if (OSIntNesting > 0) { /* See if called from ISR ... */ *perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */ return (pevent); } OS_ENTER_CRITICAL(); if (pevent->OSEventGrp != 0) { /* See if any tasks waiting on mutex */ tasks_waiting = OS_TRUE; /* Yes */ } else { tasks_waiting = OS_FALSE; /* No */ } switch (opt) { case OS_DEL_NO_PEND: /* DELETE MUTEX ONLY IF NO TASK WAITING --- */ if (tasks_waiting == OS_FALSE) { #if OS_EVENT_NAME_SIZE > 1 pevent->OSEventName[0] = '?'; /* Unknown name */ pevent->OSEventName[1] = OS_ASCII_NUL; #endif pip = (INT8U)(pevent->OSEventCnt >> 8); OSTCBPrioTbl[pip] = (OS_TCB *)0; /* Free up the PIP */ pevent->OSEventType = OS_EVENT_TYPE_UNUSED; pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */ pevent->OSEventCnt = 0; OSEventFreeList = pevent; OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; pevent_return = (OS_EVENT *)0; /* Mutex has been deleted */ } else { OS_EXIT_CRITICAL(); *perr = OS_ERR_TASK_WAITING; pevent_return = pevent; } break; case OS_DEL_ALWAYS: /* ALWAYS DELETE THE MUTEX ---------------- */ pip = (INT8U)(pevent->OSEventCnt >> 8); /* Get PIP of mutex */ prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get owner's original prio */ ptcb = (OS_TCB *)pevent->OSEventPtr; if (ptcb != (OS_TCB *)0) { /* See if any task owns the mutex */ if (ptcb->OSTCBPrio == pip) { /* See if original prio was changed */ OSMutex_RdyAtPrio(ptcb, prio); /* Yes, Restore the task's original prio */ } } while (pevent->OSEventGrp != 0) { /* Ready ALL tasks waiting for mutex */ (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK); } #if OS_EVENT_NAME_SIZE > 1 pevent->OSEventName[0] = '?'; /* Unknown name */ pevent->OSEventName[1] = OS_ASCII_NUL; #endif pip = (INT8U)(pevent->OSEventCnt >> 8); OSTCBPrioTbl[pip] = (OS_TCB *)0; /* Free up the PIP */ pevent->OSEventType = OS_EVENT_TYPE_UNUSED; pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */ pevent->OSEventCnt = 0; OSEventFreeList = pevent; /* Get next free event control block */ OS_EXIT_CRITICAL(); if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */ OS_Sched(); /* Find highest priority task ready to run */ } *perr = OS_ERR_NONE; pevent_return = (OS_EVENT *)0; /* Mutex has been deleted */ break; default: OS_EXIT_CRITICAL(); *perr = OS_ERR_INVALID_OPT; pevent_return = pevent; break; } return (pevent_return); }
OSMutexPend()函数的主要工作过程如下:① 进行运行条件检查;② 满足运行条件后,首先检查是否有Mutex可用,如果有可用的Mutex,则占用这个Mutex,调用者获得共享资源的使用权;③ 如果没有可用的Mutex,则需要检查Mutex的占用者是否需要提升优先级;④ 对需要提升优先级的占用者进行一系列处理;⑤ 将Mutex占用者的优先级改为PIP;⑥ 挂起调用者,并调用调度函数切换任务;⑦ 当调用者再次运行时,需要检查调用者是因为超时期满还是得到Mutex而运行的,并作相应处理。
void OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr) { INT8U pip; /* Priority Inheritance Priority (PIP) */ INT8U mprio; /* Mutex owner priority */ BOOLEAN rdy; /* Flag indicating task was ready */ OS_TCB *ptcb; OS_EVENT *pevent2; INT8U y; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0; #endif #if OS_ARG_CHK_EN > 0 if (perr == (INT8U *)0) { /* Validate 'perr' */ return; } if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ *perr = OS_ERR_PEVENT_NULL; return; } #endif if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */ *perr = OS_ERR_EVENT_TYPE; return; } if (OSIntNesting > 0) { /* See if called from ISR ... */ *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ return; } if (OSLockNesting > 0) { /* See if called with scheduler locked ... */ *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ return; } /*$PAGE*/ OS_ENTER_CRITICAL(); pip = (INT8U)(pevent->OSEventCnt >> 8); /* Get PIP from mutex */ /* Is Mutex available? */ if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) { pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Yes, Acquire the resource */ pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* Save priority of owning task */ pevent->OSEventPtr = (void *)OSTCBCur; /* Point to owning task's OS_TCB */ if (OSTCBCur->OSTCBPrio <= pip) { /* PIP 'must' have a SMALLER prio ... */ OS_EXIT_CRITICAL(); /* ... than current task! */ *perr = OS_ERR_PIP_LOWER; } else { OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; } return; } mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* No, Get priority of mutex owner */ ptcb = (OS_TCB *)(pevent->OSEventPtr); /* Point to TCB of mutex owner */ if (ptcb->OSTCBPrio > pip) { /* Need to promote prio of owner?*/ if (mprio > OSTCBCur->OSTCBPrio) { y = ptcb->OSTCBY; if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0) { /* See if mutex owner is ready */ OSRdyTbl[y] &= ~ptcb->OSTCBBitX; /* Yes, Remove owner from Rdy ...*/ if (OSRdyTbl[y] == 0) { /* ... list at current prio */ OSRdyGrp &= ~ptcb->OSTCBBitY; } rdy = OS_TRUE; } else { pevent2 = ptcb->OSTCBEventPtr; if (pevent2 != (OS_EVENT *)0) { /* Remove from event wait list */ if ((pevent2->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) { pevent2->OSEventGrp &= ~ptcb->OSTCBBitY; } } rdy = OS_FALSE; /* No */ } ptcb->OSTCBPrio = pip; /* Change owner task prio to PIP */ #if OS_LOWEST_PRIO <= 63 ptcb->OSTCBY = (INT8U)( ptcb->OSTCBPrio >> 3); ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x07); ptcb->OSTCBBitY = (INT8U)(1 << ptcb->OSTCBY); ptcb->OSTCBBitX = (INT8U)(1 << ptcb->OSTCBX); #else ptcb->OSTCBY = (INT8U)((ptcb->OSTCBPrio >> 4) & 0xFF); ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x0F); ptcb->OSTCBBitY = (INT16U)(1 << ptcb->OSTCBY); ptcb->OSTCBBitX = (INT16U)(1 << ptcb->OSTCBX); #endif if (rdy == OS_TRUE) { /* If task was ready at owner's priority ...*/ OSRdyGrp |= ptcb->OSTCBBitY; /* ... make it ready at new priority. */ OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; } else { pevent2 = ptcb->OSTCBEventPtr; if (pevent2 != (OS_EVENT *)0) { /* Add to event wait list */ pevent2->OSEventGrp |= ptcb->OSTCBBitY; pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; } } OSTCBPrioTbl[pip] = ptcb; } } OSTCBCur->OSTCBStat |= OS_STAT_MUTEX; /* Mutex not available, pend current task */ OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; OSTCBCur->OSTCBDly = timeout; /* Store timeout in current task's TCB */ OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ OS_EXIT_CRITICAL(); OS_Sched(); /* Find next highest priority task ready */ OS_ENTER_CRITICAL(); switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */ case OS_STAT_PEND_OK: *perr = OS_ERR_NONE; break; case OS_STAT_PEND_ABORT: *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted getting mutex */ break; case OS_STAT_PEND_TO: default: OS_EventTaskRemove(OSTCBCur, pevent); *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get mutex within TO */ break; } OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */ OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */ OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */ #if (OS_EVENT_MULTI_EN > 0) OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0; #endif OS_EXIT_CRITICAL(); }
OSMutexPost()函数用于释放Mutex。当高优先级任务想得到Mutex时,如果Mutex占用者的优先级已经被升高,那么该函数使优先级升高了的任务恢复原来的优先级。如果有多个任务在等待一个Mutex,那么其中优先级最高的任务获得Mutex。此后,该函数将调用调度函数,进行任务切换。如果没有任务在等待这个Mutex,则将Mutex的值设为0xFF,表示有mutx可用。
INT8U OSMutexPost (OS_EVENT *pevent) { INT8U pip; /* Priority inheritance priority */ INT8U prio; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0; #endif if (OSIntNesting > 0) { /* See if called from ISR ... */ return (OS_ERR_POST_ISR); /* ... can't POST mutex from an ISR */ } #if OS_ARG_CHK_EN > 0 if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ return (OS_ERR_PEVENT_NULL); } #endif if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */ return (OS_ERR_EVENT_TYPE); } OS_ENTER_CRITICAL(); pip = (INT8U)(pevent->OSEventCnt >> 8); /* Get priority inheritance priority of mutex */ prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get owner's original priority */ if (OSTCBCur != (OS_TCB *)pevent->OSEventPtr) { /* See if posting task owns the MUTEX */ OS_EXIT_CRITICAL(); return (OS_ERR_NOT_MUTEX_OWNER); } if (OSTCBCur->OSTCBPrio == pip) { /* Did we have to raise current task's priority? */ OSMutex_RdyAtPrio(OSTCBCur, prio); /* Restore the task's original priority */ } OSTCBPrioTbl[pip] = OS_TCB_RESERVED; /* Reserve table entry */ if (pevent->OSEventGrp != 0) { /* Any task waiting for the mutex? */ /* Yes, Make HPT waiting for mutex ready */ prio = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK); pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Save priority of mutex's new owner */ pevent->OSEventCnt |= prio; pevent->OSEventPtr = OSTCBPrioTbl[prio]; /* Link to new mutex owner's OS_TCB */ if (prio <= pip) { /* PIP 'must' have a SMALLER prio ... */ OS_EXIT_CRITICAL(); /* ... than current task! */ OS_Sched(); /* Find highest priority task ready to run */ return (OS_ERR_PIP_LOWER); } else { OS_EXIT_CRITICAL(); OS_Sched(); /* Find highest priority task ready to run */ return (OS_ERR_NONE); } } pevent->OSEventCnt |= OS_MUTEX_AVAILABLE; /* No, Mutex is now available */ pevent->OSEventPtr = (void *)0; OS_EXIT_CRITICAL(); return (OS_ERR_NONE); }
相关文章推荐
- Android入门(2)——点击事件的三种方式监听方式
- D3js-值域渐变地图
- 取消物理后退键的2种方法
- Android连续两次后退键退出程序
- Android组件:Fragment切换后保存状态
- scons小结
- Javascript中函数及变量定义的提升
- D3js-值域渐变地图
- ARP协议详解之ARP动态与静态条目的生命周期
- spring mvc 文件上传
- 类模版的注意事项
- 《JAVA程序设计》第一次——《猜猜看》游戏
- 使用四种框架分别实现1百万websocket常连接的服务器
- 类模版的注意事项
- eclipse中运行python脚本中有注释为中文的内容,报错:SyntaxError: Non-ASCII character '\xe5'
- Web API核查表:设计、测试、公布API时需思虑的43件事
- c语言学生信息管理系统(链表、文件)
- 算法基础:大数求和问题
- Cassandra vs MongoDB vs CouchDB vs Redis vs Riak vs HBase vs Couchbase vs OrientDB vs Aerospike vs N
- 布局之二-- RelativeLayout