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