99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

UCOS學(xué)習(xí)之互斥信號量

發(fā)布時間:2017-05-27 15:44  回復(fù):0  查看:2305   最后回復(fù):2017-05-27 15:44  

本文和大家分享的主要是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();

}

UCOS學(xué)習(xí)之互斥信號量


如上圖所示:在任務(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)問題。

  使用了互斥信號量之后的運行圖如下:


UCOS學(xué)習(xí)之互斥信號量


如圖所示, 在任務(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

您還未登錄,請先登錄

熱門帖子

最新帖子

?