FreeRTOS队列集
任務(wù)通信過程中,如果消息類型不同,使用一條隊(duì)列來實(shí)現(xiàn)則有些麻煩。
FreeRTOS 提供隊(duì)列集合,用于對多個(gè)隊(duì)列以及信號量進(jìn)行“監(jiān)聽”,只要其中不管哪一個(gè)有消息到來,都可以讓任務(wù)退出阻塞狀態(tài)。這就類似于linux網(wǎng)絡(luò)編程時(shí)的select(IO復(fù)用)。
?
?
先看一下隊(duì)列結(jié)構(gòu)體
多了一個(gè)pxQueueSetContainer成員變量,隊(duì)列所屬隊(duì)列集。
在插入隊(duì)列項(xiàng)的時(shí)候,用于查找隊(duì)列所屬的隊(duì)列集并通知正在監(jiān)聽該隊(duì)列集的任務(wù)。
/* 隊(duì)列結(jié)構(gòu)體 */ typedef struct QueueDefinition {int8_t *pcHead; /* 隊(duì)列存儲區(qū)頭部,即第一個(gè)隊(duì)列項(xiàng) */int8_t *pcWriteTo; /* 隊(duì)列項(xiàng)插入指針 */union{QueuePointers_t xQueue; /* 隊(duì)列 */SemaphoreData_t xSemaphore; /* 信號量 */}u;List_t xTasksWaitingToSend; /* 等待發(fā)送隊(duì)列項(xiàng)而阻塞的任務(wù)列表 */List_t xTasksWaitingToReceive; /* 等待接收隊(duì)列項(xiàng)而阻塞的任務(wù)列表 */volatile UBaseType_t uxMessagesWaiting; /* 已經(jīng)插入隊(duì)列項(xiàng)個(gè)數(shù) */UBaseType_t uxLength; /* 隊(duì)列項(xiàng)存儲區(qū)最多隊(duì)列項(xiàng)個(gè)數(shù) */UBaseType_t uxItemSize; /* 每個(gè)隊(duì)列項(xiàng)大小 */volatile int8_t cRxLock; /* 鎖定期間,從隊(duì)列中接收隊(duì)列項(xiàng)的次數(shù) */volatile int8_t cTxLock; /* 鎖定期間,向隊(duì)列中發(fā)送隊(duì)列項(xiàng)的次數(shù) */......#if (configUSE_QUEUE_SETS == 1)struct QueueDefinition *pxQueueSetContainer; /* 隊(duì)列所屬隊(duì)列集 */#endif...... }xQUEUE; typedef xQUEUE Queue_t;?
?
創(chuàng)建隊(duì)列集
隊(duì)列集本身也是一個(gè)隊(duì)列,將所有隊(duì)列加入隊(duì)列集,就可以對所有隊(duì)列進(jìn)行監(jiān)聽了
/* 創(chuàng)建隊(duì)列集 */ QueueSetHandle_t xQueueCreateSet(const UBaseType_t uxEventQueueLength) {QueueSetHandle_t pxQueue;/* 創(chuàng)建隊(duì)列項(xiàng)大小為sizeof(Queue_t *),長度為uxEventQueueLength的隊(duì)列 */pxQueue = xQueueGenericCreate(uxEventQueueLength, (UBaseType_t)sizeof(Queue_t *), queueQUEUE_TYPE_SET);return pxQueue; }?
?
將隊(duì)列加入隊(duì)列集
將隊(duì)列加入隊(duì)列集,本質(zhì)上就是將隊(duì)列的所屬隊(duì)列集設(shè)置為該隊(duì)列集
/* 將隊(duì)列加入隊(duì)列集 */ BaseType_t xQueueAddToSet(QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet) {BaseType_t xReturn;/* 進(jìn)入臨界區(qū) */taskENTER_CRITICAL();{/* 隊(duì)列所屬隊(duì)列集不為空 */if(((Queue_t *)xQueueOrSemaphore)->pxQueueSetContainer != NULL){/* 返回錯(cuò)誤 */xReturn = pdFAIL;}/* 隊(duì)列中已經(jīng)有隊(duì)列項(xiàng) */else if(((Queue_t *)xQueueOrSemaphore)->uxMessagesWaiting != (UBaseType_t)0){/* 返回錯(cuò)誤 */xReturn = pdFAIL;}/* 隊(duì)列不屬于任何隊(duì)列集,隊(duì)列中沒有隊(duì)列項(xiàng) */else{/* 將隊(duì)列所屬隊(duì)列集設(shè)置該隊(duì)列集 */((Queue_t *)xQueueOrSemaphore)->pxQueueSetContainer = xQueueSet;/* 返回成功 */xReturn = pdPASS;}}/* 退出臨界區(qū) */taskEXIT_CRITICAL();return xReturn; }?
?
發(fā)送隊(duì)列項(xiàng)
和普通隊(duì)列不同的是:
如果隊(duì)列被加入隊(duì)列集,則通知隊(duì)列集
如果隊(duì)列沒有加入隊(duì)列集,則通知隊(duì)列(解除那些等待的隊(duì)列)
注意:某條隊(duì)列中如果已經(jīng)存在隊(duì)列項(xiàng),再插入一個(gè)隊(duì)列項(xiàng)的時(shí)候并不會再通知隊(duì)列集,這就意味著監(jiān)聽到某條隊(duì)列有隊(duì)列項(xiàng)的時(shí)候,要一次性把隊(duì)列取干凈
/* 發(fā)送隊(duì)列項(xiàng) */ BaseType_t xQueueGenericSend(QueueHandle_t xQueue, const void *const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition) {BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired;TimeOut_t xTimeOut;Queue_t *const pxQueue = xQueue;configASSERT(pxQueue);configASSERT(!((pvItemToQueue == NULL) && (pxQueue->uxItemSize != (UBaseType_t)0U)));configASSERT(!((xCopyPosition == queueOVERWRITE) && (pxQueue->uxLength != 1)));#if ((INCLUDE_xTaskGetSchedulerState == 1) || (configUSE_TIMERS == 1)){configASSERT(!((xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED) && (xTicksToWait != 0)));}#endiffor(;;){/* 進(jìn)入臨界區(qū) */taskENTER_CRITICAL();{/* 目前已插入隊(duì)列項(xiàng)數(shù)小于最大可插入隊(duì)列數(shù)或者覆蓋型插入 */if((pxQueue->uxMessagesWaiting < pxQueue->uxLength) || (xCopyPosition == queueOVERWRITE)){traceQUEUE_SEND(pxQueue);#if (configUSE_QUEUE_SETS == 1){UBaseType_t uxPreviousMessagesWaiting = pxQueue->uxMessagesWaiting;/* 將數(shù)據(jù)拷貝到隊(duì)列項(xiàng)中 */xYieldRequired = prvCopyDataToQueue(pxQueue, pvItemToQueue, xCopyPosition);/* 該隊(duì)列被加入隊(duì)列集 */if(pxQueue->pxQueueSetContainer != NULL){/* 覆蓋型插入或者先前隊(duì)列項(xiàng)數(shù)不為0,說明已經(jīng)通知過隊(duì)列集 */if((xCopyPosition == queueOVERWRITE) && (uxPreviousMessagesWaiting != (UBaseType_t)0)){mtCOVERAGE_TEST_MARKER();}/* 通知隊(duì)列集 */else if(prvNotifyQueueSetContainer(pxQueue, xCopyPosition) != pdFALSE){queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}/* 該隊(duì)列沒有被加入隊(duì)列集 */else{/* 等待接收隊(duì)列項(xiàng)而阻塞的任務(wù)列表不為空 */if(listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToReceive)) == pdFALSE){/* 將任務(wù)從事件列表中移除一個(gè)任務(wù),并掛接到就緒列表 */if(xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToReceive)) != pdFALSE){/* 請求切換任務(wù) */queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}/* 等待接收隊(duì)列項(xiàng)而阻塞的任務(wù)列表為空 */else if(xYieldRequired != pdFALSE){queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}}#else{......}#endif/* 退出臨界區(qū) */taskEXIT_CRITICAL();/* 成功 */return pdPASS;}/* 目前隊(duì)列已經(jīng)滿了,且不是覆蓋型插入 */else{/* 阻塞時(shí)間為0 */if(xTicksToWait == (TickType_t)0){taskEXIT_CRITICAL();traceQUEUE_SEND_FAILED(pxQueue);/* 返回隊(duì)列已滿錯(cuò)誤 */return errQUEUE_FULL;}/* 當(dāng)前節(jié)拍狀態(tài)還未記錄 */else if(xEntryTimeSet == pdFALSE){/* 記錄當(dāng)前節(jié)拍狀態(tài) */vTaskInternalSetTimeOutState(&xTimeOut);/* 當(dāng)前節(jié)拍狀態(tài)已經(jīng)記錄 */xEntryTimeSet = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}}/* 退出臨界區(qū) */taskEXIT_CRITICAL();/* 掛起調(diào)度器 */vTaskSuspendAll();/* 鎖定隊(duì)列 */prvLockQueue(pxQueue);/* 檢查任務(wù)是否超時(shí),并未超時(shí) */if(xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE){/* 檢查隊(duì)列是否已滿,已經(jīng)滿了 */if(prvIsQueueFull(pxQueue) != pdFALSE){traceBLOCKING_ON_QUEUE_SEND(pxQueue);/* 將任務(wù)掛接到等待發(fā)送而阻塞的任務(wù)列表中,并將任務(wù)掛接到延時(shí)列表中 */vTaskPlaceOnEventList(&(pxQueue->xTasksWaitingToSend), xTicksToWait);/* 解鎖隊(duì)列 */prvUnlockQueue(pxQueue);/* 解除調(diào)度器掛起 */if(xTaskResumeAll() == pdFALSE){/* 請求切換 */portYIELD_WITHIN_API();}}/* 剛好隊(duì)列出現(xiàn)空位,下一次while循環(huán)重新插入 */else{/* 解鎖隊(duì)列 */prvUnlockQueue(pxQueue);/* 解除調(diào)度器掛起 */(void)xTaskResumeAll();}}/* 已經(jīng)超時(shí)或者超時(shí)之后 */else{/* 解鎖隊(duì)列 */prvUnlockQueue(pxQueue);/* 解除調(diào)度器掛起 */(void)xTaskResumeAll();traceQUEUE_SEND_FAILED(pxQueue);/* 隊(duì)列已滿 */return errQUEUE_FULL;}} }源碼中使用prvNotifyQueueSetContainer函數(shù),通知隊(duì)列集
通知隊(duì)列集,其實(shí)就是將隊(duì)列作為隊(duì)列項(xiàng)插入到隊(duì)列集中,并通知監(jiān)聽而阻塞的任務(wù)
/* 通知隊(duì)列集 */ static BaseType_t prvNotifyQueueSetContainer(const Queue_t *const pxQueue, const BaseType_t xCopyPosition) {Queue_t *pxQueueSetContainer = pxQueue->pxQueueSetContainer;BaseType_t xReturn = pdFALSE;configASSERT(pxQueueSetContainer);configASSERT(pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength);/* 隊(duì)列集還沒滿 */if(pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength){const int8_t cTxLock = pxQueueSetContainer->cTxLock;traceQUEUE_SEND(pxQueueSetContainer);/* 將隊(duì)列拷貝進(jìn)隊(duì)列集 */xReturn = prvCopyDataToQueue(pxQueueSetContainer, &pxQueue, xCopyPosition);/* 沒鎖定 */if(cTxLock == queueUNLOCKED){/* 有任務(wù)在監(jiān)聽隊(duì)列集 */if(listLIST_IS_EMPTY(&(pxQueueSetContainer->xTasksWaitingToReceive)) == pdFALSE){/* 將正在監(jiān)聽隊(duì)列集而阻塞的任務(wù)從事件列表中移除,加入就緒列表 */if(xTaskRemoveFromEventList(&(pxQueueSetContainer->xTasksWaitingToReceive)) != pdFALSE){xReturn = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}/* 鎖定 */else{/* 鎖定期間發(fā)送次數(shù)加一,解鎖的時(shí)候補(bǔ)償處理這么多次 */pxQueueSetContainer->cTxLock = (int8_t)(cTxLock + 1);}}else{mtCOVERAGE_TEST_MARKER();}return xReturn; }?
?
監(jiān)聽隊(duì)列集
監(jiān)聽隊(duì)列集,其實(shí)就是等待從隊(duì)列集中取出隊(duì)列指針
/* 監(jiān)聽隊(duì)列集 */ QueueSetMemberHandle_t xQueueSelectFromSet(QueueSetHandle_t xQueueSet, TickType_t const xTicksToWait) {QueueSetMemberHandle_t xReturn = NULL;/* 從隊(duì)列集中取出隊(duì)列指針 */(void)xQueueReceive((QueueHandle_t)xQueueSet, &xReturn, xTicksToWait);return xReturn; }?
總結(jié)
以上是生活随笔為你收集整理的FreeRTOS队列集的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 朱啸虎:几百亿资金今年注入小程序,你能抓
- 下一篇: makefile之通配符(4)