μC/OS-II的任務(wù)之間的通訊與同步
程序清單L6.11發(fā)出一個信號量
INT8UOSSemPost(OS_EVENT*pevent)
{
OS_ENTER_CRITICAL();
if(pevent->OSEventType!=OS_EVENT_TYPE_SEM){(1)
OS_EXIT_CRITICAL();
return(OS_ERR_EVENT_TYPE);
}
if(pevent->OSEventGrp){(2)
OSEventTaskRdy(pevent,(void*)0,OS_STAT_SEM);(3)
OS_EXIT_CRITICAL();
OSSched();(4)
return(OS_NO_ERR);
}else{
if(pevent->OSEventCnt65535){
pevent->OSEventCnt++;(5)
OS_EXIT_CRITICAL();
return(OS_NO_ERR);
}else{
OS_EXIT_CRITICAL();
return(OS_SEM_OVF);
}
}
}
6.6.4 無等待地請求一個信號量,OSSemAccept()
當(dāng)一個任務(wù)請求一個信號量時,如果該信號量暫時無效,也可以讓該任務(wù)簡單地返回,而不是進(jìn)入睡眠等待狀態(tài)。這種情況下的操作是由OSSemAccept()函數(shù)完成的,其源代碼見程序清單L6.12。該函數(shù)在最開始也是檢查參數(shù)指針pevent指向的事件控制塊是否是由OSSemCreate()函數(shù)建立的[L6.12(1)],接著從該信號量的事件控制塊中取出當(dāng)前計數(shù)值[L6.12(2)],并檢查該信號量是否有效(計數(shù)值是否為非0值)[L6.12(3)]。如果有效,則將信號量的計數(shù)值減1[L6.12(4)],然后將信號量的原有計數(shù)值返回給調(diào)用函數(shù)[L6.12(5)]。調(diào)用函數(shù)需要對該返回值進(jìn)行檢查。如果該值是0,說明該信號量無效。如果該值大于0,說明該信號量有效,同時該值也暗示著該信號量當(dāng)前可用的資源數(shù)。應(yīng)該注意的是,這些可用資源中,已經(jīng)被該調(diào)用函數(shù)自身占用了一個(該計數(shù)值已經(jīng)被減1)。中斷服務(wù)子程序要請求信號量時,只能用OSSemAccept()而不能用OSSemPend(),因為中斷服務(wù)子程序是不允許等待的。
程序清單L6.12無等待地請求一個信號量
INT16UOSSemAccept(OS_EVENT*pevent)
{
INT16Ucnt;
OS_ENTER_CRITICAL();
if(pevent->OSEventType!=OS_EVENT_TYPE_SEM){(1)
OS_EXIT_CRITICAL();
return(0);
}
cnt=pevent->OSEventCnt;(2)
if(cnt>0){(3)
pevent->OSEventCnt--;(4)
}
OS_EXIT_CRITICAL();
return(cnt);(5)
}
6.6.5 查詢一個信號量的當(dāng)前狀態(tài),OSSemQuery()
在應(yīng)用程序中,用戶隨時可以調(diào)用函數(shù)OSSemQuery()[程序清單L6.13]來查詢一個信號量的當(dāng)前狀態(tài)。該函數(shù)有兩個參數(shù):一個是指向信號量對應(yīng)事件控制塊的指針pevent。該指針是在生產(chǎn)信號量時,由OSSemCreate()函數(shù)返回的;另一個是指向用于記錄信號量信息的數(shù)據(jù)結(jié)構(gòu)OS_SEM_DATA(見uCOS_II.H)的指針pdata。因此,調(diào)用該函數(shù)前,用戶必須先定義該結(jié)構(gòu)變量,用于存儲信號量的有關(guān)信息。在這里,之所以使用一個新的數(shù)據(jù)結(jié)構(gòu)的原因在于,調(diào)用函數(shù)應(yīng)該只關(guān)心那些和特定信號量有關(guān)的信息, 而不是象OS_EVENT數(shù)據(jù)結(jié)構(gòu)包含的很全面的信息。
該數(shù)據(jù)結(jié)構(gòu)只包含信號量計數(shù)值.OSCnt和等待任務(wù)列表.OSEventTbl[]、.OSEventGrp,而OS_EVENT中還包含了另外的兩個域.OSEventType和.OSEventPtr。
和其它與信號量有關(guān)的函數(shù)一樣,OSSemQuery()也是先檢查pevent指向的事件控制塊是否是OSSemCreate()產(chǎn)生的[L6.13(1)],然后將等待任務(wù)列表[L6.13(2)]和計數(shù)值[L6.13(3)]
從OS_EVENT結(jié)構(gòu)拷貝到OS_SEM_DATA結(jié)構(gòu)變量中去。
程序清單L6.13查詢一個信號量的狀態(tài)
INT8UOSSemQuery(OS_EVENT*pevent,OS_SEM_DATA*pdata)
{
INT8Ui;
INT8U*psrc;
INT8U*pdest;
OS_ENTER_CRITICAL();
if(pevent->OSEventType!=OS_EVENT_TYPE_SEM){(1)
OS_EXIT_CRITICAL();
return(OS_ERR_EVENT_TYPE);
}
pdata->OSEventGrp=pevent->OSEventGrp;(2)
psrc=pevent->OSEventTbl[0];
pdest=pdata->OSEventTbl[0];
for(i=0;i
*pdest++=*psrc++;
}
pdata->OSCnt=pevent->OSEventCnt;(3)
OS_EXIT_CRITICAL();
return(OS_NO_ERR);
}
6.7 郵箱
郵箱是μC/OS-II中另一種通訊機(jī)制, 它可以使一個任務(wù)或者中斷服務(wù)子程序向另一個任務(wù)發(fā)送一個指針型的變量。該指針指向一個包含了特定“消息”的數(shù)據(jù)結(jié)構(gòu)。為了在μC/OS-II中使用郵箱,必須將OS_CFG.H中的OS_MBOX_EN常數(shù)置為1。
使用郵箱之前,必須先建立該郵箱。該操作可以通過調(diào)用OSMboxCreate()函數(shù)來完成(見下節(jié)),并且要指定指針的初始值。一般情況下,這個初始值是NULL,但也可以初始化一個郵
箱,使其在最開始就包含一條消息。如果使用郵箱的目的是用來通知一個事件的發(fā)生(發(fā)送一
條消息),那么就要初始化該郵箱為NULL,因為在開始時,事件還沒有發(fā)生。如果用戶用郵箱
來共享某些資源,那么就要初始化該郵箱為一個非NULL的指針。在這種情況下,郵箱被當(dāng)成一
個二值信號量使用。
μC/OS-II提供了5種對郵箱的操作:OSMboxCreate(),OSMboxPend(),OSMboxPost(),
OSMboxAccept()和 OSMboxQuery()函數(shù)。圖F6.6描述了任務(wù)、中斷服務(wù)子程序和郵箱之間的關(guān)
系,這里用符號“I”表示郵箱。郵箱包含的內(nèi)容是一個指向一條消息的指針。一個郵箱只能包
含一個這樣的指針(郵箱為滿時),或者一個指向NULL的指針(郵箱為空時)。從圖F6.6可以看出,任務(wù)或者中斷服務(wù)子程序可以調(diào)用函數(shù)OSMboxPost(),但是只有任務(wù)可以調(diào)用函數(shù)OSMboxPend()和OSMboxQuery()。
圖F6.6任務(wù)、中斷服務(wù)子程序和郵箱之間的關(guān)系
6.7.1 建立一個郵箱,OSMboxCreate()
程序清單L6.14是OSMboxCreate()函數(shù)的源代碼,基本上和函數(shù)OSSemCreate()相似。不同之處在于事件控制塊的類型被設(shè)置成OS_EVENT_TYPE_MBOX[L6.14(1)], 以及使用.OSEventPtr域來容納消息指針,而不是使用.OSEventCnt域[L6.14(2)]。
評論