在UCOS的信号量使用过程中,我们经常会用的是二值信号量,而在二值信号两种用的醉的情况就是互斥信号量。互斥信号是本身是一种二进制信号,具有超出uCOS-II提供的一般信号机制的特性。由于其特殊性,UCOS的作者将其独立成章,单独对待。组织了一套对于互斥信号量管理的单独函数。互斥信号量具有以下特点: 1) 降解优先级反转。 2) 实现对资源的独占式访问(二值信号量)。
在应用程序中使用互斥信号是为了减少优先级翻转问题,当一个高优先级的任务需要的资源被一个低优先级的任务使用时,就会发生优先级翻转问题。为了减少优先级翻转问题,内核可以提高的优先级任务的优先级,先于高优先级的任务运行,释放占用的资源。
为了实现互斥,实时内核需要具有支持在同一优先级具有多个任务的能力。不幸的是,UC/OS-II不允许在相同的优先级有多个任务,必须只有一个任务。但是我们有另外的方法解决这个问题。可以把需要资源的高优先级任务上面的一个任务使用Mutex保留,允许提高的优先级任务的优先级。
举一个mutexes信号工作的例子,如l下面的程序所示。
其中有三个任务可以使用共同的资源,为了访问这个资源,每个任务必须在互斥信号 ResourceMutex上等待(pend),任务#1有最高优先级10,任务#2优先级为15,任务#3优先级为20,一个没有使用的正好在最高优先级之上的优先级#9用来作为优先级继承优先级。如main()所示,代码中(1)进行uC/OS-II初始化,并通过调用OSMutexCreate()代码中(2)创建了一个互斥信号。需要注意的是,OSMutexCreate()函数使用PIP最为参数。然后创建三个任务代码中(3),启动uC/OS-II 代码中(4).
假设任务运行了一段时间,在某个时间点,任务#3最先访问了共同的资源,并得到了互斥信号,任务#3运行了一段时间后被任务#1抢占。任务#1需要使用这个资源,并通过调用OSMutexPend()企图获得互斥信号,这种情况下,OSMutexPend()会发现一个高优先级的任务需要这个资源,就会把任务#3的优先级提高到9,同时强迫进行上下文切换退回到任务#3执行。 任务#3可以继续执行然后释放占用的共同资源。任务#3通过调用OSMutexPost()释放占用的mutex信号,OSMutexPost()会发现mutex被一个优先级提升的低优先级的任务占有,就会把任务#3的优先级返回到20。把资源释放给任务#1使用,执行上下文切换到任务#1
-----------------------------------------------------------------
OS_EVENT *ResourceMutex;
OS_STK TaskPrio10Stk[1000];
OS_STK TaskPrio15Stk[1000];
OS_STK TaskPrio20Stk[1000];
void main (void)
{
INT8U err;
OSInit(); /* (1) */
/* ---------- 应用程序初始化 ---------- */
OSMutexCreate(9, &err); /* (2) */
OSTaskCreate(TaskPrio10, (void *)0, &TaskPrio10Stk[999], 10); /* (3) */
OSTaskCreate(TaskPrio15, (void *)0, &TaskPrio15Stk[999], 15);
OSTaskCreate(TaskPrio20, (void *)0, &TaskPrio20Stk[999], 20);
/* ---------- Application Initialization ---------- */
OSStart(); /* (4) */
}
void TaskPrio10 (void *pdata)
{
INT8U err;
pdata = pdata;
while (1) {
/* --------- 应用程序代码 ---------- */
OSMutexPend(ResourceMutex, 0, &err);
/* ------- 访问贡献资源 ------ */
OSMutexPost(ResourceMutex);
/* --------- 应用程序代码 ---------- */
}
}
void TaskPrio15 (void *pdata)
{
INT8U err;
pdata = pdata;
while (1) {
/* ---------应用程序代码 ---------- */
OSMutexPend(ResourceMutex, 0, &err);
/* ------- 访问共享资源 ------ */
OSMutexPost(ResourceMutex);
/* --------- 应用程序代码 ---------- */
}
}
void TaskPrio20 (void *pdata)
{
INT8U err;
pdata = pdata;
while (1) {
/* ---------应用程序代码---------- */
OSMutexPend(ResourceMutex, 0, &err);
/* -------访问共享资源------ */
OSMutexPost(ResourceMutex);
/* ---------应用程序代码---------- */
}
}
上面代码为互斥信号使用示例
uC/OS-II'互斥信号包含三个元素,一个flag表示当前mutex是否能够获得(0或1);一个priority表示使用这个mutex的任务,以防一个高优先级的任务需要访问mutex;还包括一个等待这个mutex的任务列表。
为了启动uC/OS-II’s mutex服务,应该在OS_CFG.H中设置OS_MUTEX_EN=1。在使用一个互斥信号之前应该首先创建它,创建一个mutex信号通过调用OSMutexCreate()完成,mutex的初始值总是设置为1,表示资源可以获得。
uC/OS-II提供了六种访问互斥信号量的操作 OSMutexCreate(), OSMutexDel(),OSMutexPend(), OSMutexPost(), OSMutexAccept() and OSMutexQuery().
展示了任务和互斥信号量的关系。一个互斥信号量只能被任务访问。在以后的资料中使用钥匙符号表示互斥信号。钥匙符号表明互斥信号用来访问共享资源。没有钥匙就无法访问。只有得到钥匙的任务才有资格访问共享资源