In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-15 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
This article focuses on "the characteristics and workflow of FreeRTOS message queue". Interested friends may wish to have a look at it. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn the characteristics and workflow of FreeRTOS message queue.
FreeRTOS message queuing
FreeRTOS-based applications consist of a separate set of tasks-each task is a program with independent permissions. The communication and synchronization between these independent tasks are generally based on the IPC communication mechanism provided by the operating system, while all the communication and synchronization mechanisms in FreeRTOS are based on queues. Message queue is a data structure commonly used for inter-task communication, which can transmit information between tasks, interrupts and tasks, and enables tasks to receive messages of variable length from other tasks or interrupts. The task can read messages from the queue, suspend the read task when the message in the queue is empty, and the user can also specify the time of the suspended task; when there is a new message in the queue, the pending read task is awakened and processed the new message. message queuing is an asynchronous way of communication.
Queue characteristics 1. Data storage
The queue can hold a limited number of data units of a certain length. The maximum number of units that a queue can hold is called the "depth" of the queue. You need to set its depth and the size of each unit when the queue is created. Typically, queues are used as FIFO (first-in, first-out) buffers, where data is written at the end of the queue and read out from the beginning of the queue. Of course, it is also possible to write at the beginning of the queue. Writing data to the queue is to copy and store the data in the queue through byte copy; reading data from the queue causes the data copy in the queue to be deleted.
two。 Read blocking
When a task tries to read a queue, it can specify a blocking timeout. During this time, if the queue is empty, the task will remain blocked to wait for the queue data to be valid. When other tasks or interrupt service routines write data to the queue they are waiting for, the task will automatically shift from blocking to ready. When the waiting time exceeds the specified blocking time, even if there is no valid data in the queue, the task will automatically shift from the blocked state to the ready state. Because queues can be read by multiple tasks, for a single queue, there may also be multiple tasks blocking to wait for the queue data to be valid. In this case, once the queue data is valid, only one task will be unblocked, which is the highest priority of all waiting tasks. If all waiting tasks have the same priority, then the unblocked task will be the longest waiting task.
To put it beside the point, there are broadcast messages in ucos. When there are multiple tasks blocking on the queue, and when sending messages, you can choose to broadcast messages, then these blocked tasks can be unblocked.
3. Write blocking
In contrast to read blocking, a task can also specify a blocking timeout when writing to the queue. This time is the longest time when the written queue is full and the task enters the blocking state to wait for the queue space to be valid. Because queues can be written by multiple tasks, for a single queue, there may also be multiple tasks blocking to wait for the queue space to be valid. In this case, once the queue space is valid, only one task will be unblocked, which is the highest priority of all waiting tasks. If all waiting tasks have the same priority, then the unblocked task will be the longest waiting task.
Workflow of message queuing 1. Send a message
Either the task or the interrupt service program can send a message to the message queue. When sending a message, if the queue is not full or override is allowed, FreeRTOS will copy the message to the end of the message queue, otherwise, it will block according to the blocking timeout specified by the user. During this period, if the queue is not allowed, the task will remain blocked to wait for the queue to be allowed to join the queue. When other tasks read data from the queue they are waiting for (the queue is not full), the task will automatically change from blocking to ready. When the waiting time of a task exceeds the specified blocking time, even if it is not allowed to join the queue, the task will automatically transfer from the blocking state to the ready state, and the task or interrupt program that sends the message will receive an error code errQUEUE_FULL. The process of sending an emergency message is almost the same as sending a message, except that when an emergency message is sent, it is sent at the beginning of the message queue rather than at the end of the queue, so that the recipient can receive the emergency message first. so that the message can be processed in time. The following is the sending API interface of the message queue, and the FromISR in the function indicates that it is used in the interrupt.
1 / *-* / 2 BaseType_t xQueueGenericSend (QueueHandle_t xQueue, (1) 3 const void * const pvItemToQueue (2) 4 TickType_t xTicksToWait, (3) 5 const BaseType_t xCopyPosition) (4) 6 {7 BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired 8 TimeOut_t xTimeOut; 9 Queue_t * const pxQueue = (Queue_t *) xQueue;10 11 / * some assertion operations * / 12 13 for (;;) {14 taskENTER_CRITICAL (); (5) 15 {16 / * queue not full * / 17 if ((pxQueue- > uxMessagesWaiting)
< pxQueue->UxLength) 18 | | (xCopyPosition = = queueOVERWRITE) {(6) 19 traceQUEUE_SEND (pxQueue); 20 xYieldRequired = 21 prvCopyDataToQueue (pxQueue, pvItemToQueue, xCopyPosition) (7) 22 23 / * deleted partial code using queue set * / 24 / * if a task is waiting to get this message queue * / 25 if (listLIST_IS_EMPTY (& (pxQueue- > xTasksWaitingToReceive)) = = pdFALSE) {(8) 26 / * recover the task from blocking * / 27 If (xTaskRemoveFromEventList (28 & (pxQueue- > xTasksWaitingToReceive))! = pdFALSE) {(9) 29 / * if the priority of the restored task is higher than that of the currently running task 30 then a task switch is required * / 31 queueYIELD_IF_USING_PREEMPTION () (10) 32} else {33 mtCOVERAGE_TEST_MARKER () 34} 35} else if (xYieldRequired! = pdFALSE) {36 / * if there is no waiting task, task switching is required for successful copy * / 37 queueYIELD_IF_USING_PREEMPTION () (11) 38} else {39 mtCOVERAGE_TEST_MARKER (); 40} 41 42 taskEXIT_CRITICAL (); (12) 43 return pdPASS 44} 45 / * queue full * / 46 else {(13) 47 if (xTicksToWait = = (TickType_t) 0) {48 / * if the user does not specify a blocking timeout, exit * / 49 taskEXIT_CRITICAL () (14) 50 traceQUEUE_SEND_FAILED (pxQueue); 51 return errQUEUE_FULL 52} else if (xEntryTimeSet = = pdFALSE) {53 / * initialize the blocking timeout structure variable, initialize the time xTickCount to enter 54 blocking and the number of overflows xNumOfOverflows * / 55 vTaskSetTimeOutState (& xTimeOut); (15) 56 xEntryTimeSet = pdTRUE 57} else {58 mtCOVERAGE_TEST_MARKER (); 59} 60} 61} 62 taskEXIT_CRITICAL (); (16) 63 / * pending scheduler * / 64 vTaskSuspendAll () 65 / * queue locked * / 66 prvLockQueue (pxQueue) 67 68 / * check whether the timeout has passed * / 69 if (xTaskCheckForTimeOut (& xTimeOut, & xTicksToWait) = = pdFALSE) {(17) 70 / * if the queue is still full * / 71 if (prvIsQueueFull (pxQueue)! = pdFALSE) {(18) 72 traceBLOCKING_ON_QUEUE_SEND (pxQueue) 73 / * add the current task to the queue's waiting send list 74 and the blocking delay list, which is the user-specified timeout xTicksToWait * / 75 vTaskPlaceOnEventList (76 & (pxQueue- > xTasksWaitingToSend), xTicksToWait) (19) 77 / * queue unlocking * / 78 prvUnlockQueue (pxQueue); (20) 79 80 / * recovery scheduler * / 81 if (xTaskResumeAll () = = pdFALSE) {82 portYIELD_WITHIN_API () 83} 84} else {85 / * queue has free message space, allowed to join the queue * / 86 prvUnlockQueue (pxQueue); (21) 87 (void) xTaskResumeAll () 88} 89} else {90 / * timeout has expired, exit * / 91 prvUnlockQueue (pxQueue); (22) 92 (void) xTaskResumeAll (); 93 94 traceQUEUE_SEND_FAILED (pxQueue); 95 return errQUEUE_FULL 96} 97} 98} 99 / *
If the blocking time is not 0, the task will enter the block because it is waiting to join the queue. In the process of setting the task to block, the system does not want other tasks and interruptions to operate the queue's xTasksWaitingToReceive list and xTasksWaitingToSend list, because it may cause other tasks to unblock, which may cause priority reversal. For example, task A has a lower priority than the current task, but when the current task enters blocking, task An is unblocked for other reasons, which is obviously absolutely prohibited. So FreeRTOS uses the suspend scheduler to prevent other tasks from operating on the queue, because suspending the scheduler means that the task cannot be switched and is not allowed to call API functions that may cause the task to switch. However, suspending the scheduler does not prohibit interrupts, and the interrupt service function can still manipulate the queue blocking list, which may unblock tasks and may cause context switching, which is also not allowed. Therefore, the FreeRTOS solution is not only to suspend the scheduler, but also to lock the queue to prevent any interrupts from manipulating the queue. Let's take a look at the flowchart:
Compared to the send function called in the task, the function called in the interrupt is simpler, and there is no task blocking the operation. After inserting data into the function xQueueGenericSend, it checks whether there is a task waiting in the waiting list, and if so, it will be ready. If the priority of the restored task is higher than the current task, the task switch will be triggered; however, the function called in the interrupt returns a parameter indicating whether the task switch needs to be triggered, and does not switch the task during the interrupt. The function called in the task has the operation of locking and unlocking the queue, and the event list of the queue cannot be modified when the queue is locked. The processing of sending a message in an interruption is: when the queue is locked, after the new data is inserted into the queue, it will not be directly restored because of the tasks waiting to be received, but will add up the count. When the queue is unlocked, several tasks will be restored according to this count. When the queue is full, the function returns directly instead of blocking waiting, because blocking is not allowed in interrupts!
1 BaseType_t xQueueGenericSendFromISR (2 QueueHandle_t xQueue, 3 const void * const pvItemToQueue, 4 / * does not trigger task switching in the interrupt function, but returns a tag * / 5 BaseType_t * const pxHigherPriorityTaskWoken, 6 const BaseType_t xCopyPosition) 7 {8 BaseType_t xReturn; 9 UBaseType_t uxSavedInterruptStatus;10 Queue_t * const pxQueue = (Queue_t *) xQueue;1112 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR () 13 {14 / / determine whether the queue has room to insert new content 15 if ((pxQueue- > uxMessagesWaiting)
< pxQueue->Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.