本文和大家分享的主要是UCOS中的互斥信號量相關(guān)內(nèi)容,一起來看看吧,希望對大家學(xué)習(xí)UCOS有所幫助。
二值信號量主要用于進(jìn)行共享資源的獨占式訪問,比如我們用一個變量來標(biāo)志一個資源是否可用,當(dāng)這個變量為1的時候表示資源可用,當(dāng)這個資源為0的時候表示資源不可用,但是二值信號量容易產(chǎn)生優(yōu)先級反轉(zhuǎn),影響系統(tǒng)的實時性?;コ庑盘柫恳话阌糜诮到鈨?yōu)先級反轉(zhuǎn),優(yōu)先級反轉(zhuǎn)就是高優(yōu)先級的任務(wù)的優(yōu)先級被拉低了。具體如下:
我們有三個任務(wù)Task1,Task2,Task3,三個任務(wù)的優(yōu)先級依次降低。
void Task1()
{
while(1)
{
OSSemPend(); //獲取信號量
......
OSSemPost(); //釋放信號量
}
}
void Task2()
{
while(1)
{
//注意任務(wù)2不需要信號量
}
}
void Task3()
{
while(1)
{
OSSemPend(); //獲取信號量
OSSemPost(); //釋放信號量
}
}
void main()
{
OSInit();
CreateTask(Task1); //1 最高
CreateTask(Task2); //2
CreateTask(Task3);
OSStart();
}
如上圖所示:在任務(wù)2獲得信號量的時候,任務(wù)1恢復(fù)就緒態(tài)之后因為沒有獲得信號量而掛起,所以任務(wù)3繼續(xù)執(zhí)行,直到任務(wù)3執(zhí)行完畢之后,任務(wù)1才開始執(zhí)行。 雖然任務(wù)1的優(yōu)先級最高,但是因為信號量的原因而是任務(wù)1的優(yōu)先級降到任務(wù)3的優(yōu)先級水平。而且任務(wù)2加重了優(yōu)先級反轉(zhuǎn)的程度。
當(dāng)我們使用了互斥信號量之后,就可以在某種程度上緩解優(yōu)先級反轉(zhuǎn)的問題了。當(dāng)高優(yōu)先級的任務(wù)請求互斥信號量時,如果低優(yōu)先級的任務(wù)占有該信號量,則先提升低優(yōu)先級任務(wù)的優(yōu)先級,使之盡快執(zhí)行完以釋放互斥信號量,這樣高優(yōu)先級的任務(wù)也能盡快執(zhí)行,在某種程度上緩解了優(yōu)先級反轉(zhuǎn)問題。
使用了互斥信號量之后的運行圖如下:
如圖所示, 在任務(wù)3執(zhí)行的過程中,任務(wù)1請求互斥信號量,提升任務(wù)3的優(yōu)先級到最高,使任務(wù)3盡快執(zhí)行完,任務(wù)3執(zhí)行完后釋放信號量,任務(wù)1開始執(zhí)行。
UCOS_II中互斥信號量相關(guān)的函數(shù)主要在os_mutex.c中,核心代碼如下:
void OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
INT8U pip; //繼承優(yōu)先級
INT8U mprio; //現(xiàn)在占有該信號量的優(yōu)先級
BOOLEAN rdy; //當(dāng)前任務(wù)是否就緒標(biāo)志
OS_TCB *ptcb;
OS_EVENT *pevent2;
INT8U y;
OS_ENTER_CRITICAL();
//該信號量的繼承優(yōu)先級
pip = (INT8U)(pevent->OSEventCnt >> 8);
//該互斥信號量還沒有被占用
if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE)
{
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;
//直接以當(dāng)前優(yōu)先級占用該信號量
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;
pevent->OSEventPtr = (void *)OSTCBCur;
if (OSTCBCur->OSTCBPrio <= pip)
{
OS_EXIT_CRITICAL();
//繼承優(yōu)先級比當(dāng)前任務(wù)的優(yōu)先級還小
*err = OS_ERR_PIP_LOWER;
}
else
{
OS_EXIT_CRITICAL();
//繼承優(yōu)先級至少比當(dāng)前任務(wù)的優(yōu)先級高
*err = OS_NO_ERR;
}
return;
}
//占用該信號量的任務(wù)的優(yōu)先級
mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
//現(xiàn)在占有該信號量的任務(wù)的TCB
ptcb = (OS_TCB *)(pevent->OSEventPtr);
//占有該信號量的任務(wù)的優(yōu)先級比繼承優(yōu)先級小時才會進(jìn)行反轉(zhuǎn)
if (ptcb->OSTCBPrio > pip)
{
//占有該信號量的任務(wù)的優(yōu)先級小于當(dāng)前任務(wù)的優(yōu)先級進(jìn)行反轉(zhuǎn)
if (mprio > OSTCBCur->OSTCBPrio)
{
//從就緒表中移除現(xiàn)在占有該信號量的任務(wù)
y = ptcb->OSTCBY;
if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0)
{
OSRdyTbl[y] &= ~ptcb->OSTCBBitX;
if (OSRdyTbl[y] == 0)
{
OSRdyGrp &= ~ptcb->OSTCBBitY;
}
//占有該信號量的任務(wù)已經(jīng)處于就緒態(tài)
rdy = OS_TRUE;
}
else //占有該信號量的任務(wù)現(xiàn)在在系統(tǒng)的等待列表中
{
//占有該信號量的任務(wù)的ECB
pevent2 = ptcb->OSTCBEventPtr;
if (pevent2 != (OS_EVENT *)0)
{
//將占有該信號量的任務(wù)從該信號量的等待列表中移除
if ((pevent2->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) {
pevent2->OSEventGrp &= ~ptcb->OSTCBBitY;
}
}
//占有改信號量的任務(wù)現(xiàn)在還沒有就緒
rdy = OS_FALSE;
}
//更改占有該信號量的任務(wù)的優(yōu)先級
ptcb->OSTCBPrio = pip;
ptcb->OSTCBY = (INT8U)( ptcb->OSTCBPrio >> 3);
ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x07);
ptcb->OSTCBBitY = (INT8U)(1 << ptcb->OSTCBY);
ptcb->OSTCBBitX = (INT8U)(1 << ptcb->OSTCBX);
if (rdy == OS_TRUE)
{
//如果之前占有該信號量的任務(wù)已近處于就緒態(tài)了
//就將提升之后的優(yōu)先級加入到就緒表中
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
}
else
{
pevent2 = ptcb->OSTCBEventPtr;
if (pevent2 != (OS_EVENT *)0)
{
//占有該信號量的任務(wù)處于等待列表中就把提升
//優(yōu)先級之后的任務(wù)加入到該信號量的等待列表中
pevent2->OSEventGrp |= ptcb->OSTCBBitY;
pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
}
}
//徹底占用該優(yōu)先級
OSTCBPrioTbl[pip] = ptcb;
}
}
OSTCBCur->OSTCBStat |= OS_STAT_MUTEX;
OSTCBCur->OSTCBPendTO = OS_FALSE;
OSTCBCur->OSTCBDly = timeout;
OS_EventTaskWait(pevent);
OS_EXIT_CRITICAL();
//重新調(diào)度
OS_Sched();
OS_ENTER_CRITICAL();
//該任務(wù)等待超時
if (OSTCBCur->OSTCBPendTO == OS_TRUE)
{
OS_EventTO(pevent);
OS_EXIT_CRITICAL();
*err = OS_TIMEOUT;
return;
}
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
}
來源:CSDN