(uC/OS-II学习笔记)关于共享资源与信号量
uC/os-ii中任务间相互通信的媒介叫做事件。
关于OS_EVENT数据结构
#if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0u) typedef struct os_event { INT8U OSEventType; /* Type of event control block (see OS_EVENT_TYPE_xxxx) */ void *OSEventPtr; /* Pointer to message or queue structure */ INT16U OSEventCnt; /* Semaphore Count (not used if other EVENT type) */ OS_PRIO OSEventGrp; /* Group corresponding to tasks waiting for event to occur */ OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */ #if OS_EVENT_NAME_EN > 0u INT8U *OSEventName; #endif } OS_EVENT; #endif
OSEventType:事件类型(信号量、互斥信号量、邮箱、消息列队)
OSEventCnt:计数器
OSEventPtr:指向一个消息
OSEventGrp与OSEventTbl[OS_EVENT_TBL_SIZE]:等待事件任务(类似于OSRdyTbl[]和OSRdyGrp)
事件块实质是一个链表
不同的任务如果使用共享资源,可能会出错。信号量类似于共享资源访问的一个标志。
比如……我们把串口终端当做一个资源。
TASK_1与TASK_2(TASK1优先级高于TASK_2)
OS_EVENT MyFirstSem; char * CommonzSoure = ""; void Task_1(void *pdata) { U32 i; #if OS_CRITICAL_METHOD == 3 //关中断的方法为3 OS_CPU_SR cpu_sr; #endif OS_ENTER_CRITICAL(); OS_CPU_SysTickInit(100000000/OS_TICKS_PER_SEC); OS_EXIT_CRITICAL(); OSStatInit(); //统计任务 优先级最低 MyFirstSem = *(OSSemCreate(1)); //PIT0_Init(50000000); UART4_Init(115200); init_LED(); pdata = pdata; while(1) { CommonzSoure = "TASK1 Using Common source "; for(i=0;CommonzSoure[i];i++) Uart4_SendByte(CommonzSoure[i]); OSTimeDly(1); } } void Task_2(void *pdata) { U32 i; pdata = pdata; while(1) { CommonzSoure = "TASK2 Using Common source "; for(i=0;CommonzSoure[i];i++) Uart4_SendByte(CommonzSoure[i]); } }
任务1发送数据“TASK1 Using Common source”
任务2发送数据“TASK2 Using Common source”
任务切换的时候 数据发送会出错。(比如我们把串口终端当做一个实体的打印机)
如果加入信号量(标记共享资源)
OS_EVENT MyFirstSem; char * CommonzSoure = ""; void Task_1(void *pdata) { U32 i; U8 err; #if OS_CRITICAL_METHOD == 3 //关中断的方法为3 OS_CPU_SR cpu_sr; #endif OS_ENTER_CRITICAL(); OS_CPU_SysTickInit(100000000/OS_TICKS_PER_SEC); OS_EXIT_CRITICAL(); OSStatInit(); //统计任务 优先级最低 MyFirstSem = *(OSSemCreate(1)); //PIT0_Init(50000000); UART4_Init(115200); init_LED(); pdata = pdata; while(1) { OSSemPend(&MyFirstSem,0,&err); CommonzSoure = "TASK1 Using Common source "; for(i=0;CommonzSoure[i];i++) Uart4_SendByte(CommonzSoure[i]); OSSemPost(&MyFirstSem); OSTimeDly(1); } } void Task_2(void *pdata) { U32 i; U8 err; pdata = pdata; while(1) { OSSemPend(&MyFirstSem,0,&err); CommonzSoure = "TASK2 Using Common source "; for(i=0;CommonzSoure[i];i++) Uart4_SendByte(CommonzSoure[i]); OSSemPost(&MyFirstSem); } }
OSSemAccept()可以无等待请求一个信号量。
该函数只简单返回OSEventCnt的值,并在OSEventCnt值为真的时候做OSEventCnt--;
调用OSSemAccept()函数,……不过目测资源都被TASK_2独占了。→_→
同样,信号量也可以用于限制某个资源的任务个数。
关于优先级反转与互斥信号量。
信号量的使用可能会导致优先级反转。
比如……
由于任务C(低)得到信号量,任务A等待。任务B的优先级高于任务C,故任务B先运行。直到任务B,C运行完,任务C释放信号量,优先级最高的任务A才得到CPU资源。
防止优先级反转的方法,在任务C得到信号量时把任务C的优先级升高,结束后再恢复。
uC/OS-II,互斥信号量机制可以防止优先级反转。
由于uC/OS-II不支持相同优先级,互斥信号量机制,可以使某个人物得到信号量时,优先级提到共享相同资源任务最高。
OSMutexCreate(INT8U prio,INT8U *error)
创建互斥信号量。
uC/OS-II互斥信号量支持六种操作:创建、删除、等待、释放、无条件等待获取互斥信号量、获取互斥信号量当前状态。