日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

os_mutex.c(全)

發布時間:2025/3/21 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 os_mutex.c(全) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  • 無等待地獲取互斥型信號量?OSMutexAccept (OS_EVENT ?*pevent,INT8U ?*perr):
  • 創建互斥型信號量OS_EVENT ?*OSMutexCreate (INT8U ? prio,INT8U ?*perr)
  • 刪除信號量OS_EVENT ?*OSMutexDel (OS_EVENT ?*pevent,INT8U ?opt,INT8U ?*perr)
  • 等待互斥型信號量void ?OSMutexPend (OS_EVENT ?*pevent,INT32U ?timeout,INT8U ?*perr)
  • 釋放一個互斥型信號量?OSMutexPost (OS_EVENT *pevent)
  • 查詢互斥量OSMutexQuery (OS_EVENT ?*pevent,OS_MUTEX_DATA ?*p_mutex_data)

?OSMutexAccept (OS_EVENT ?*pevent,INT8U ? ? *perr):

若是信號量可用就使用信號量,若是不可用就去執行其他代碼,不阻塞等待。 若是有可用的,那么其操作跟請求互斥信號量OSMutexPend的信號量可用時執行代碼部分是一樣的。 /*$PAGE*/ /*2018/2/19 ********************************************************************************************************* * ACCEPT MUTUAL EXCLUSION SEMAPHORE * 無等待地獲取互斥型信號量 * Description: This function checks the mutual exclusion semaphore to see if a resource is available. * Unlike OSMutexPend(), OSMutexAccept() does not suspend the calling task if the resource is * not available or the event did not occur. *描述: 檢查互斥型信號量,以判斷某資源是否可以使用,與 OSMutexPend()不同的是,若資源不能使用,則調用 OSMutexAccept()函數的任務并不被掛起, OSMutexAccept()僅查詢狀態。 * Arguments : pevent is a pointer to the event control block *參數: pevent:指向事件控制塊的指針 * perr is a pointer to an error code which will be returned to your application: * OS_ERR_NONE if the call was successful. * OS_ERR_EVENT_TYPE if 'pevent' is not a pointer to a mutex * OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer * OS_ERR_PEND_ISR if you called this function from an ISR * OS_ERR_PIP_LOWER If the priority of the task that owns the Mutex is * HIGHER (i.e. a lower number) than the PIP. This error * indicates that you did not set the PIP higher (lower * number) than ALL the tasks that compete for the Mutex. * Unfortunately, this is something that could not be * detected when the Mutex is created because we don't know * what tasks will be using the Mutex. * perr: 指向錯誤碼的指針。可以有以下幾種選擇:OS_ERR_NONE:無錯誤OS_ERR_EVENT_TYPE:pevent不是指向mutex類型的指針OS_ERR_PEVENT_NULL:pevent為空指針OS_ERR_PEND_ISR:在中斷服務子程序中調用OS_ERR_PIP_LOWER:正在使用mutex的任務優先級高于PIP。 * Returns : == OS_TRUE if the resource is available, the mutual exclusion semaphore is acquired * == OS_FALSE a) if the resource is not available * b) you didn't pass a pointer to a mutual exclusion semaphore * c) you called this function from an ISR *返回值: ==OS_TRUE:資源可以獲得,互斥型信號量可以獲得==OS_FALSE:a)無法獲得資源b)沒有指向互斥型信號量的指針c)從中斷服務子程序中調用該功能 * Warning(s) : This function CANNOT be called from an ISR because mutual exclusion semaphores are * intended to be used by tasks only. 警告:該功能不能從中斷中調用,因為互斥型信號量只能被任務調用。 ********************************************************************************************************* */#if OS_MUTEX_ACCEPT_EN > 0u BOOLEAN OSMutexAccept (OS_EVENT *pevent,INT8U *perr) {INT8U pip; /* Priority Inheritance Priority (PIP)優先級繼承優先級*/#if OS_CRITICAL_METHOD == 3u /*中斷類型被設置為類型3*/OS_CPU_SR cpu_sr = 0u;#endif#ifdef OS_SAFETY_CRITICAL /*安全中斷*/if (perr == (INT8U *)0) {OS_SAFETY_CRITICAL_EXCEPTION();}#endif#if OS_ARG_CHK_EN > 0u /*參數檢查*/if (pevent == (OS_EVENT *)0) { *perr = OS_ERR_PEVENT_NULL;return (OS_FALSE);}#endifif (pevent->OSEventType != OS_EVENT_TYPE_MUTEX)/*有效化事件控制塊類型*/{ *perr = OS_ERR_EVENT_TYPE;return (OS_FALSE);}if (OSIntNesting > 0u) /*判斷是否從中斷服務子程序中調用*/{ *perr = OS_ERR_PEND_ISR;return (OS_FALSE);}OS_ENTER_CRITICAL(); /*進入中斷*/pip = (INT8U)(pevent->OSEventCnt >> 8u); /* 從mutex中獲得PIP,pip存放在OSEventCnt的高八位中*/if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE)/*/獲得Mutex的值(0或1),OSEventCnt相與0x00ff后判斷。OSEventCnt低8為0xff*/{pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /*如果Mutex(高8位PIP)有效,將PIP保存到OSEventCnt的高8位(相與0xffoo)*/pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /*把該任務的優先級寫到OSEventCnt的低8位(相或OSTCBPrio)*/pevent->OSEventPtr = (void *)OSTCBCur; /*將Mutex的事件控制塊ECB鏈接到該任務的任務控制塊*/if (OSTCBCur->OSTCBPrio <= pip) /*如果當前TCB的優先級數值不大于pip,即優先級高*/{ OS_EXIT_CRITICAL(); /*退出中斷*/*perr = OS_ERR_PIP_LOWER; /*將錯誤類型設置為OS_ERR_PIP_LOWER,無法執行該任務*/} else /*如果當前TCB的優先級小于pip*/{ OS_EXIT_CRITICAL(); /*退出中斷*/*perr = OS_ERR_NONE;/*成功調用該函數*/}return (OS_TRUE);/*檢查狀態,可以獲得互斥型信號量*/}OS_EXIT_CRITICAL();/*退出中斷*/*perr = OS_ERR_NONE;/*將錯誤類型設置為無錯誤*/return (OS_FALSE); /*檢查狀態后確認不可以獲得互斥型信號量*/ } #

要注意該函數返回的是一個布爾值,表示能否獲得互斥量。

在這個函數中,需要對下面幾行進行解釋:

pip = (INT8U)(pevent->OSEventCnt >> 8u); /* 從mutex中獲得PIP,pip存放在OSEventCnt的高八位中*/ if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE)

pip是priority inheritance priority,優先級繼承優先級。對于互斥型信號量,可能存在很多任務爭奪一個的情況,此時,可能發生優先級反轉現象(可以參考之前文章OS_CORE.C(6),點擊打開鏈接)。pip就是為了防止優先級反轉設置的。簡單來說,如果當前任務優先級比繼承優先級低,不會反轉,不需要pip。如果比繼承優先級高,會反轉,那么將當前任務優先級設置為pip,這樣就不會發生反轉了。

OSEventCnt的低8位存放的是OS_MUTEX_AVAILABLE,如果if判斷后檢查結果仍為OS_MUTEX_AVAILABLE,則說明互斥鎖沒有被占用,這時候就要保存當前運行任務的優先級到OSEventCnt的低8位中,語句為:

pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;

然后比較一下當前任務的優先級是否比創建時的繼承優先級低(優先級值大),如果當前任務的優先級比繼承優先級高(數值小),則返回錯誤,語句為:

if (OSTCBCur->OSTCBPrio <= pip)????????/*如果當前TCB的優先級數值不大于pip,即優先級高*/{ OS_EXIT_CRITICAL(); /*退出中斷*/*perr = OS_ERR_PIP_LOWER;/*將錯誤類型設置為OS_ERR_PIP_LOWER,無法執行該任務*/}

因為繼承優先級是為了防止優先級翻轉而設定,如果當前任務優先級比繼承優先級低則不需要擔心優先級反轉,則返回正確值。


創建互斥型信號量OS_EVENT *OSMutexCreate(INT8U prio,INT8U *perr):

/*$PAGE*/ /*2018/2/19 ********************************************************************************************************* * CREATE A MUTUAL EXCLUSION SEMAPHORE * 創建互斥型信號量 * Description: This function creates a mutual exclusion semaphore. *描述:該功能用來新建互斥型信號量。 * Arguments : prio is the priority to use when accessing the mutual exclusion semaphore. In * other words, when the semaphore is acquired and a higher priority task * attempts to obtain the semaphore then the priority of the task owning the * semaphore is raised to this priority. It is assumed that you will specify * a priority that is LOWER in value than ANY of the tasks competing for the * mutex. *參數: --prio:獲得互斥型信號量的任務的優先級。換句話說,當有任務已經獲得了信號量,但是更高優先級任務嘗試獲得該信號量時,占有信號量的任務將其優先級提高到高優先級。。此時任務的優先級比所有競爭mutex的任務優先級都高。 * perr is a pointer to an error code which will be returned to your application: * OS_ERR_NONE if the call was successful. * OS_ERR_CREATE_ISR if you attempted to create a MUTEX from an ISR * OS_ERR_PRIO_EXIST if a task at the priority inheritance priority * already exist. * OS_ERR_PEVENT_NULL No more event control blocks available. * OS_ERR_PRIO_INVALID if the priority you specify is higher that the * maximum allowed (i.e. > OS_LOWEST_PRIO) * --perr:指向錯誤碼的指針,取值如下:OS_ERR_NONE:無錯誤;OS_ERR_CREATE_ISR:從中斷服務子程序中創建mutexOS_ERR_PRIO_EXIST:優先級為PIP的任務已經存在;OS_ERR_PEVENT_NULL:沒有可用的事件控制塊OS_ERR_PRIO_INVALID:定義的優先級非法,其值大于OS_LOWEST_PRIO. * Returns : != (void *)0 is a pointer to the event control clock (OS_EVENT) associated with the * created mutex. * == (void *)0 if an error is detected. *返回值: !=0 返回一個指針 ,該指針指向分配給mutex的事件控制塊。==0 有錯誤,返回空指針。 * Note(s) : 1) The LEAST significant 8 bits of '.OSEventCnt' are used to hold the priority number * of the task owning the mutex or 0xFF if no task owns the mutex. * * 2) The MOST significant 8 bits of '.OSEventCnt' are used to hold the priority number * to use to reduce priority inversion. 注釋: 1)OSEventCnt的低八位用來表示擁有互斥量任務的優先級,如果沒有任務擁有該互斥量,低八位為0xff2)OSEventCnt的高八位存放的優先級是用來減少優先級反轉 ********************************************************************************************************* */OS_EVENT *OSMutexCreate (INT8U prio,INT8U *perr) {OS_EVENT *pevent;/*指向事件控制塊的指針*/ mutex首先會檢查傳入優先級的任務的TCB有沒有已經被使用,如果傳入優先級已經被使用,則創建失敗,返回錯誤,如果參數傳入的優先級的TCB沒有被占用,則設置為reserved,保證該TCB不會被其他任務使用。語句如下: OS_ENTER_CRITICAL();/*進入中斷*/if (OSTCBPrioTbl[prio] != (OS_TCB *)0) /*檢查傳入優先級的任務的TCB是否被占用*/{ OS_EXIT_CRITICAL(); *perr = OS_ERR_PRIO_EXIST; return ((OS_EVENT *)0);}OSTCBPrioTbl[prio] = OS_TCB_RESERVED;/*如果沒有被占用,則設置為reserved*/

再檢查是否有空閑的事件控制塊,如果沒有返回空指針,如果有,進行相關操作:

pevent = OSEventFreeList;/*得到一個事件控制塊 */if (pevent == (OS_EVENT *)0) /*如果沒有空閑的事件控制塊*/{ OSTCBPrioTbl[prio] = (OS_TCB *)0; /*將優先級表對應的位置清0 */OS_EXIT_CRITICAL();/*退出中斷*/*perr = OS_ERR_PEVENT_NULL; /*將錯誤碼設置為OS_ERR_PEVENT_NULL*/return (pevent);/*返回一個空指針*/}/*如果有空閑的事件控制塊*/OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; /*調整事件空閑列表*/OS_EXIT_CRITICAL();/*退出中斷*/pevent->OSEventType = OS_EVENT_TYPE_MUTEX;/*將事件類型設置為mutex*/pevent->OSEventCnt = (INT16U)((INT16U)prio << 8u) | OS_MUTEX_AVAILABLE;pevent->OSEventPtr = (void *)0; /*沒有任務使用mutex*/#if OS_EVENT_NAME_EN > 0upevent->OSEventName = (INT8U *)(void *)"?";/*如果事件有名稱,設置為未命名*/#endifOS_EventWaitListInit(pevent);/*事件等待列表初始化*/

這幾行語句中解釋一下:

pevent->OSEventCnt = (INT16U)((INT16U)prio << 8u) | OS_MUTEX_AVAILABLE;

prio左移8位,將優先級存放在OSEventCnt中的高八位,再與OS_MUTEX_AVAILABLE進行或運算,即OSEventCnt的低八位00與OS_MUTEX_AVAILABLE進行運算,如果運算結果為全ff,則說明可以獲得mutex,否則不可以獲得。


刪除信號量OS_EVENT ?*OSMutexDel (OS_EVENT ?*pevent,INT8U ?opt,INT8U ?*perr):(部分代碼)

/*$PAGE*/ /*2018/2/19 ********************************************************************************************************* * DELETE A MUTEX * 刪除信號量 * Description: This function deletes a mutual exclusion semaphore and readies all tasks pending on the it. *描述:該功能用來刪除互斥量并且將所有的任務就緒 * Arguments : pevent is a pointer to the event control block associated with the desired mutex. *參數: --pevent:指向事件控制塊的指針 * opt determines delete options as follows: * opt == OS_DEL_NO_PEND Delete mutex ONLY if no task pending * opt == OS_DEL_ALWAYS Deletes the mutex even if tasks are waiting. * In this case, all the tasks pending will be readied. * --opt:兩種刪除方式:OS_DEL_NO_PEND:只有沒有任務掛起時才能刪除該互斥量;OS_DEL_ALWAYS:無論有沒有掛起都刪除,這種情況下,所有的任務都從掛起狀態轉化為就緒態。 * perr is a pointer to an error code that can contain one of the following values: * OS_ERR_NONE The call was successful and the mutex was deleted * OS_ERR_DEL_ISR If you attempted to delete the MUTEX from an ISR * OS_ERR_INVALID_OPT An invalid option was specified * OS_ERR_TASK_WAITING One or more tasks were waiting on the mutex * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer. * --perr:指向錯誤碼的指針,可以有以下值:OS_ERR_NONE:無錯誤;OS_ERR_DEL_ISR:從中斷服務子程序刪除;OS_ERR_INVALID_OPT:opt為無效值;OS_ERR_TASK_WAITING:一個或者多個任務正在等待mutex;OS_ERR_EVENT_TYPE:沒有指向mutex的指針;OS_ERR_PEVENT_NULL:pevent為空指針。 * Returns : pevent upon error * (OS_EVENT *)0 if the mutex was successfully deleted. *返回值:如果mutex已經刪除,則返回空指針;如果mutex沒能刪除,則返回pevent * Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of * the mutex MUST check the return code of OSMutexPend(). *注釋: 1)該功能必須小心使用,因為其他任務可能會用到mutex。需要該信號量的任務必須檢測OSMutexPend()的返回值。 * 2) This call can potentially disable interrupts for a long time. The interrupt disable * time is directly proportional to the number of tasks waiting on the mutex. * 2)調用該函數時不能被中斷。中斷時間與等待該信號量的任務數量有關。 * 3) Because ALL tasks pending on the mutex will be readied, you MUST be careful because the * resource(s) will no longer be guarded by the mutex. * 3)因為在刪除信號量之后,所有掛起的任務都自動轉為就緒態,所以你必須小心,因為資源此時不再被mutex控制。 * 4) IMPORTANT: In the 'OS_DEL_ALWAYS' case, we assume that the owner of the Mutex (if there * is one) is ready-to-run and is thus NOT pending on another kernel object or * has delayed itself. In other words, if a task owns the mutex being deleted, * that task will be made ready-to-run at its original priority.4)重點:在OS_DEL_ALWAYS情況下,我們任務mutex的擁有者(假設只有一個)已經準備運行,并且不在其他內核對象中等待(掛起)或者自身延遲。換句話說,如果擁有互斥量的任務被刪除了,該任務將會以之前原始的優先級存在。 ********************************************************************************************************* */#if OS_MUTEX_DEL_EN > 0u OS_EVENT *OSMutexDel (OS_EVENT *pevent,INT8U opt,INT8U *perr) {BOOLEAN tasks_waiting;/*布爾值看是否有任務正在等待*/OS_EVENT *pevent_return;/*返回值*/INT8U pip; /*繼承優先級*/INT8U prio;/*原始優先級*/OS_TCB *ptcb;/*指向TCB的指針*/

先檢查是否有任務正在等待信號量。然后選擇刪除方式,進行刪除。

OS_ENTER_CRITICAL();/*進入中斷*/if (pevent->OSEventGrp != 0u)/*檢查是否有任務正在等待該信號量*/{ tasks_waiting = OS_TRUE; } else{tasks_waiting = OS_FALSE; }switch (opt) /*選擇刪除方式*/{case OS_DEL_NO_PEND:/*沒有等待信號量的任務時才刪除*/if (tasks_waiting == OS_FALSE) /*沒有任務等待*/{#if OS_EVENT_NAME_EN > 0upevent->OSEventName = (INT8U *)(void *)"?";/*如果有名稱,將名稱設置為未命名*/#endifpip = (INT8U)(pevent->OSEventCnt >> 8u);/*將OSEventCnt的高八位賦值給pip,獲得繼承優先級*/OSTCBPrioTbl[pip] = (OS_TCB *)0; /*在優先級表中釋放pip所在的tcb */pevent->OSEventType = OS_EVENT_TYPE_UNUSED;/*將事件類型設置為未使用類型*/pevent->OSEventPtr = OSEventFreeList;/*將事件控制塊返回給空閑事件列表 */pevent->OSEventCnt = 0u;OSEventFreeList = pevent;/*更新空閑事件列表*/OS_EXIT_CRITICAL();/*退出中斷*/*perr = OS_ERR_NONE;pevent_return = (OS_EVENT *)0;/*信號量已經被刪除,返回空指針*/} else/*有任務等待*/{OS_EXIT_CRITICAL();/*退出中斷*/*perr = OS_ERR_TASK_WAITING;pevent_return = pevent;}break;case OS_DEL_ALWAYS:/*無論怎樣都刪除*/pip = (INT8U)(pevent->OSEventCnt >> 8u); /*得到繼承優先級*/prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);/*得到原始的優先級*/ptcb = (OS_TCB *)pevent->OSEventPtr;/*指向TCB的指針*/if (ptcb != (OS_TCB *)0)/*如果有空閑的TCB*/{ /* See if any task owns the mutex */if (ptcb->OSTCBPrio == pip) /*看原始的優先級是否改變了,即是否解決過優先級反轉*/{ OSMutex_RdyAtPrio(ptcb, prio); /*原始優先級改變,將其存儲。待任務完成后恢復*/}}while (pevent->OSEventGrp != 0u) /*如果有事件組,即有任務在等待該信號量*/{ (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK);/*將所有任務轉為就緒態*/}#if OS_EVENT_NAME_EN > 0upevent->OSEventName = (INT8U *)(void *)"?";/*將事件名稱設置為未命名*/#endifpip = (INT8U)(pevent->OSEventCnt >> 8u);/*獲得pip*/OSTCBPrioTbl[pip] = (OS_TCB *)0; pevent->OSEventType = OS_EVENT_TYPE_UNUSED;pevent->OSEventPtr = OSEventFreeList; pevent->OSEventCnt = 0u;OSEventFreeList = pevent; OS_EXIT_CRITICAL();if (tasks_waiting == OS_TRUE) /*如果有任務等待*/{ OS_Sched();/*在就緒任務中找到優先級最高的任務進行調度*/}*perr = OS_ERR_NONE;pevent_return = (OS_EVENT *)0;break;default:/*其他情況*/OS_EXIT_CRITICAL();*perr = OS_ERR_INVALID_OPT;/*選擇無效*/pevent_return = pevent;break;}return (pevent_return); } #endif

該函數較為簡單,不贅述。


等待互斥型信號量void ?OSMutexPend (OS_EVENT ?*pevent,INT32U timeout,INT8U ?*perr):

/*$PAGE*/ /*2018/2/19 ********************************************************************************************************* * PEND ON MUTUAL EXCLUSION SEMAPHORE * 等待互斥型信號量 * Description: This function waits for a mutual exclusion semaphore. *描述:該功能用來等待互斥型信號量 * Arguments : pevent is a pointer to the event control block associated with the desired mutex. *參數: --pevent:指向事件控制塊的指針 * timeout is an optional timeout period (in clock ticks). If non-zero, your task will * wait for the resource up to the amount of time specified by this argument. * If you specify 0, however, your task will wait forever at the specified * mutex or, until the resource becomes available. * --timeout:可選擇的時間超時片。如果不為0,任務將等待資源直到時間到了該參數規定的時間。超時后,將不再等待。如果為0,任務將永遠處于等待,直到資源可以獲得。 * perr is a pointer to where an error message will be deposited. Possible error * messages are: * OS_ERR_NONE The call was successful and your task owns the mutex * OS_ERR_TIMEOUT The mutex was not available within the specified 'timeout'. * OS_ERR_PEND_ABORT The wait on the mutex was aborted. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex * OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer * OS_ERR_PEND_ISR If you called this function from an ISR and the result * would lead to a suspension. * OS_ERR_PIP_LOWER If the priority of the task that owns the Mutex is * HIGHER (i.e. a lower number) than the PIP. This error * indicates that you did not set the PIP higher (lower * number) than ALL the tasks that compete for the Mutex. * Unfortunately, this is something that could not be * detected when the Mutex is created because we don't know * what tasks will be using the Mutex. * OS_ERR_PEND_LOCKED If you called this function when the scheduler is locked * --perr:指向錯誤信息的指針。有可能的錯誤信息如下:OS_ERR_NONE:無錯誤;OS_ERR_TIMEOUT:超時錯誤;OS_ERR_PEND_ABORT:等待信號量的任務被取消;OS_ERR_EVENT_TYPE:沒有指向mutex的指針;OS_ERR_PEVENT_NULL:pevent是空指針;OS_ERR_PEND_ISR:從中斷服務子程序中調用該功能;OS_ERR_PIP_LOWER:當前任務優先級比pip高。 * Returns : none *返回值:無 * Note(s) : 1) The task that owns the Mutex MUST NOT pend on any other event while it owns the mutex. *注釋:1)擁有信號量的任務不能再其他事件中處于掛起狀態。 * 2) You MUST NOT change the priority of the task that owns the mutex2)不能改變擁有mutex的任務的優先級。 ********************************************************************************************************* */void OSMutexPend (OS_EVENT *pevent,INT32U timeout,INT8U *perr) {INT8U pip; /*繼承優先級*/INT8U mprio; /*擁有信號量的任務的優先級*/BOOLEAN rdy; /*標志任務是否就緒*/OS_TCB *ptcb;/*指向TCB的指針*/OS_EVENT *pevent2;/*指向事件控制塊的指針*/INT8U y;檢測互斥量是否為可獲得的。如果可獲得,則判斷當前任務的優先級和pip優先級高低。如果不可獲得,需要判斷兩次:第一判斷擁有互斥量任務的優先級與pip優先級高低;第二判斷擁有互斥量任務的優先級與當前任務優先級的高低。

如果檢測互斥量是可獲得的,表示沒有任務使用互斥鎖,這時候運行該函數的任務將獲得互斥鎖并退出。如果不是可獲得的,表示一個新的任務在嘗試獲得互斥鎖,并且互斥鎖已經被占用時的操作。代碼如下:

OS_ENTER_CRITICAL();/*進入中斷*/pip = (INT8U)(pevent->OSEventCnt >> 8u);/*獲得PIP,繼承優先級*//*檢測互斥量是否為可獲得的*/if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE){pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;/*修改高8位的數據,這個時候高8位數據不變,還是表示繼承優先級,低8位清零*/pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;/*將申請任務的優先級保存在低8位之中。低八位不可能全部都為零,所以依舊可以表示信號量是否被占用*/pevent->OSEventPtr = (void *)OSTCBCur; /*OSEventPtr指針指向任務控制塊 */if (OSTCBCur->OSTCBPrio <= pip)/*如果當前任務的優先級比pip優先級高*/{ OS_EXIT_CRITICAL(); *perr = OS_ERR_PIP_LOWER;}else /*當前任務優先級低*/{OS_EXIT_CRITICAL();*perr = OS_ERR_NONE;}return;}

上面這一段代碼是互斥量為可獲得的。

下面這段代碼為互斥量不可獲得的:

/*如果該互斥量不可獲得*/mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /*得到擁有互斥量的任務的優先級*/ptcb = (OS_TCB *)(pevent->OSEventPtr); /* 指針指向擁有互斥量的TCB*/if (ptcb->OSTCBPrio > pip) /*獲得互斥量的任務的優先級比pip優先級低*/{ if (mprio > OSTCBCur->OSTCBPrio)/*獲得互斥量任務的優先級比當前任務優先級低*/{y = ptcb->OSTCBY;if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0u) /*看擁有互斥量的任務是否就緒*/{ OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;/*如果就緒,將其從就緒表中移除*/if (OSRdyTbl[y] == 0u){ OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;/*從就緒組中移除*/}rdy = OS_TRUE;/*將就緒標志設置為true*/} else/*擁有互斥量的任務沒就緒*/{pevent2 = ptcb->OSTCBEventPtr;/*pevent2指向擁有互斥量的事件*/if (pevent2 != (OS_EVENT *)0) /*如果該事件不為空,將其從事件表中刪除*/{ y = ptcb->OSTCBY;pevent2->OSEventTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;if (pevent2->OSEventTbl[y] == 0u) {pevent2->OSEventGrp &= (OS_PRIO)~ptcb->OSTCBBitY;}}rdy = OS_FALSE; /*將其就緒狀態設置為false*/}ptcb->OSTCBPrio = pip; /*將有互斥量的任務的優先級改為pip */#if OS_LOWEST_PRIO <= 63uptcb->OSTCBY = (INT8U)( ptcb->OSTCBPrio >> 3u);ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x07u);#elseptcb->OSTCBY = (INT8U)((INT8U)(ptcb->OSTCBPrio >> 4u) & 0xFFu);ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x0Fu);#endifptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY);ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);if (rdy == OS_TRUE)/*就緒狀態為true*/{/*如果該任務處于就緒態,那么這個任務已不是處在它原來優先級上的就緒態*/ OSRdyGrp |= ptcb->OSTCBBitY;OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;} else/*就緒狀態為false*/{pevent2 = ptcb->OSTCBEventPtr;if (pevent2 != (OS_EVENT *)0) /*將事件控制塊添加到事件等待列表中*/{ pevent2->OSEventGrp |= ptcb->OSTCBBitY;pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;}}OSTCBPrioTbl[pip] = ptcb;/*使占用mutex的任務以PIP優先級進入就緒態*/}}

上述過程如下圖所示:


此外還想多說一句:

OSTCBPrioTbl[pip] = ptcb;/*使占用mutex的任務以PIP優先級進入就緒態*/

下面這行語句為什么一定要讓任務以pip優先級進入就緒態?

個人理解是:對互斥量的操作中,pip的設置是為了防止優先級反轉。在操作時,要時刻保持任務是以最高優先級存在,否則就可能發生反轉。

如果互斥量不可獲取,進行完上面的判斷和操作后,后續的操作為:

OSTCBCur->OSTCBStat |= OS_STAT_MUTEX; /*無法獲得互斥量,將該任務掛起*/OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;/*掛起狀態設置為OS_STAT_PEND_OK*/OSTCBCur->OSTCBDly = timeout;OS_EventTaskWait(pevent); /*任務處于阻塞狀態,知道事件發生或超時*/ OS_EXIT_CRITICAL();/*退出中斷*/OS_Sched(); /* 找到就緒的最高優先級任務進行調度*/OS_ENTER_CRITICAL();/*進入中斷*/switch (OSTCBCur->OSTCBStatPend)/*看掛起的原因是什么?超時還是任務被取消*/{ case OS_STAT_PEND_OK:*perr = OS_ERR_NONE;break;case OS_STAT_PEND_ABORT:*perr = OS_ERR_PEND_ABORT; break;case OS_STAT_PEND_TO:default:OS_EventTaskRemove(OSTCBCur, pevent);*perr = OS_ERR_TIMEOUT; break;}OSTCBCur->OSTCBStat = OS_STAT_RDY; /*將任務狀態設置為就緒態*/OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /*清除掛起狀態 */OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* 清除事件指針*/ #if (OS_EVENT_MULTI_EN > 0u)OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0; #endifOS_EXIT_CRITICAL();/*退出中斷*/ }

釋放一個互斥型信號量OSMutexPost (OS_EVENT *pevent):

/*$PAGE*/ /*2018/2/19 ********************************************************************************************************* * POST TO A MUTUAL EXCLUSION SEMAPHORE * 釋放一個互斥型信號量 * Description: This function signals a mutual exclusion semaphore *描述:調用OSMutexPost()可以發出mutex * Arguments : pevent is a pointer to the event control block associated with the desired mutex. *參數: --pevent:指向有互斥量的事件控制塊的指針。 * Returns : OS_ERR_NONE The call was successful and the mutex was signaled. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex * OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer * OS_ERR_POST_ISR Attempted to post from an ISR (not valid for MUTEXes) * OS_ERR_NOT_MUTEX_OWNER The task that did the post is NOT the owner of the MUTEX. * OS_ERR_PIP_LOWER If the priority of the new task that owns the Mutex is * HIGHER (i.e. a lower number) than the PIP. This error * indicates that you did not set the PIP higher (lower * number) than ALL the tasks that compete for the Mutex. * Unfortunately, this is something that could not be * detected when the Mutex is created because we don't know * what tasks will be using the Mutex.返回值:OS_ERR_NONE:調用成功,發出mutex;OS_ERR_EVENT_TYPE:沒有指向mutex的指針;OS_ERR_PEVENT_NULL:pevent為空指針;OS_ERR_POST_ISR:從中斷服務子程序中調用;OS_ERR_NOT_MUTEX_OWNER:發出信號的任務沒有占用互斥量。OS_ERR_PIP_LOWER:擁有互斥量的任務的優先級比pip高。 ********************************************************************************************************* */INT8U OSMutexPost (OS_EVENT *pevent) {INT8U pip;/*繼承優先級*/INT8U prio;#if OS_CRITICAL_METHOD == 3u OS_CPU_SR cpu_sr = 0u;#endifif (OSIntNesting > 0u){ return (OS_ERR_POST_ISR); }#if OS_ARG_CHK_EN > 0uif (pevent == (OS_EVENT *)0) { return (OS_ERR_PEVENT_NULL);}#endifif (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { return (OS_ERR_EVENT_TYPE);}OS_ENTER_CRITICAL();/*進入中斷*/pip = (INT8U)(pevent->OSEventCnt >> 8u); /*獲取pip*/prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);/*獲取擁有互斥量的任務的原始優先級*/if (OSTCBCur != (OS_TCB *)pevent->OSEventPtr)/*當前任務沒有占有互斥量*/{ OS_EXIT_CRITICAL();/*退出中斷*/return (OS_ERR_NOT_MUTEX_OWNER);//發出mutex的任務實際上并不占用mutex}if (OSTCBCur->OSTCBPrio == pip) /*當前任務優先級是pip,不需要提高優先級*/{ OSMutex_RdyAtPrio(OSTCBCur, prio); /*保存任務原始優先級,任務完成后進行恢復*/}OSTCBPrioTbl[pip] = OS_TCB_RESERVED; /*將pip對應在優先級表上的值設為reserved*/if (pevent->OSEventGrp != 0u) /*如果有任務正在等待互斥量,將最高優先級任務設置為就緒態*/{ prio = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK);/*轉為就緒態任務的優先級*/pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /*新占用mutex的任務保存高8位(PIP) */pevent->OSEventCnt |= prio;/*將新任務優先級存放在低八位*/pevent->OSEventPtr = OSTCBPrioTbl[prio];/*指針指向新任務的TCB*/if (prio <= pip) /*當前任務比pip優先級高*/{ OS_EXIT_CRITICAL();/*退出中斷*/ OS_Sched();/*找到最高優先級任務進行調度*/return (OS_ERR_PIP_LOWER);/*返回錯誤值*/} else/*當前任務比pip優先級低*/{OS_EXIT_CRITICAL();/*退出中斷*/OS_Sched();/*找到最高優先級任務進行調度*/return (OS_ERR_NONE);/*返回無錯*/}}/*如果沒有任務等待互斥量*/pevent->OSEventCnt |= OS_MUTEX_AVAILABLE; /*互斥量是可獲得的 */pevent->OSEventPtr = (void *)0;OS_EXIT_CRITICAL();return (OS_ERR_NONE); }

該函數實際上是通知是否mutex為空閑的。如果當前的任務沒有占用該互斥量,返回OS_ERR_NOT_MUTEX_OWNER,即發出mutex的任務不占用互斥量。如果當前任務占用互斥量,看看是否有任務正在等待這個互斥量。如果有任務等待,那么在當前任務完成之前,將等待列表中的優先級最高的任務轉為就緒態。等當前任務完成,該任務就可以執行了。如果沒有任務等待該互斥量,就只簡單的發出“該互斥量是可獲得的”信號即可。


查詢互斥量信息OSMutexQuery (OS_EVENT ?*pevent,?OS_MUTEX_DATA ?*p_mutex_data):

/*$PAGE*/ /*2018/2/19 ********************************************************************************************************* * QUERY A MUTUAL EXCLUSION SEMAPHORE * 查詢互斥量 * Description: This function obtains information about a mutex *描述:該功能獲得關于互斥量的信息。 * Arguments : pevent is a pointer to the event control block associated with the desired mutex *參數: --pevent:指向需要互斥量的事件控制塊的指針 * p_mutex_data is a pointer to a structure that will contain information about the mutex * -- p_mutex_data :指向結構體的指針,該結構體包含互斥量的信息 * Returns : OS_ERR_NONE The call was successful and the message was sent * OS_ERR_QUERY_ISR If you called this function from an ISR * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer * OS_ERR_PDATA_NULL If 'p_mutex_data' is a NULL pointer * OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non mutex.返回值:OS_ERR_NONE:調用成功,消息也被發出。OS_ERR_QUERY_ISR:從中斷服務子程序中調用該函數;OS_ERR_PEVENT_NULL:pevent為空指針;OS_ERR_PDATA_NULL:p_mutex_data為空指針;OS_ERR_EVENT_TYPE:獲得消息對象錯誤。 ********************************************************************************************************* */#if OS_MUTEX_QUERY_EN > 0u INT8U OSMutexQuery (OS_EVENT *pevent,OS_MUTEX_DATA *p_mutex_data) {INT8U i;OS_PRIO *psrc;OS_PRIO *pdest; OS_ENTER_CRITICAL();/*進入中斷*/p_mutex_data->OSMutexPIP = (INT8U)(pevent->OSEventCnt >> 8u);/*獲取pip*/p_mutex_data->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);/*獲取擁有互斥量的任務的優先級*/if (p_mutex_data->OSOwnerPrio == 0xFFu) /*如果占用mutex任務的優先級為255時*/{p_mutex_data->OSValue = OS_TRUE; /*當前mutex的值。1表示可以使用。*/} else{p_mutex_data->OSValue = OS_FALSE;//當前mutex的值。0表示不能使用}/*將事件(互斥型信號量)結構中的等待任務列表復制到pdata數據結構中*/p_mutex_data->OSEventGrp = pevent->OSEventGrp; /*等待事件的任務組中的內容傳送到狀態數據結構中*/psrc = &pevent->OSEventTbl[0];/*保存pevent->OSEventTbl[0]對應的地址*/pdest = &p_mutex_data->OSEventTbl[0];/*保存pdata->OSEventTbl[0]對應的地址*/for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) {*pdest++ = *psrc++;/*地址指針繼續下移一個類型地址,獲取互斥型信號量的值*/}OS_EXIT_CRITICAL();/*退出中斷*/return (OS_ERR_NONE); } #endif 將任務恢復到之前到優先級static ?void ?OSMutex_RdyAtPrio (OS_TCB ?*ptcb,INT8U ?prio):

該功能是將之前為了防止優先級反轉而提高的任務的優先級恢復。


到此,OS_mutex.c文件就看完了。

這個文件重點是介紹信號量的獲取、建立、刪除、掛起等待、查詢和釋放(通知)。

總結

以上是生活随笔為你收集整理的os_mutex.c(全)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。