 Hello, let's do some more advanced exercise on queues using two senders and blocking mechanism. Here we can see in illustration how the task can be sent to the blocked state, one accessing the queue. In this example we've got the following components, a queue of length of four elements, the same size, the sender task and the receiver task, which executes first. At the beginning, a receiver task tries to read the data from the queue. As the queue is empty, task is sent to the blocked state. In the next phase, receiver tries to read the data from the queue again. This time the queue is empty, so receiver is sent to blocked state again. Just after it, sender task is sending message 1 to the queue. It is forcing scheduler to move the receiver task from blocked state to ready state. In our case we are using timeouts to get requests, thus in a third phase, receiver tries again to read the data from the queue, this time successfully. So it can continue its execution. In the fourth phase, there is no activity in the queue. Both tasks operate in ready state. Let's have a closer look on queue blocking mechanism with combination to CMC-SOS version to API. After a sender is calling OS message queue put to send the data to the queue, it can do the following operations. If there is no free space in the queue, the sender task is blocked for setable time. This time is specified within one of the arguments of this function, OS message queue put. So it can be blocked for this time. Then it will continue execution, that's on the next instruction, but of course without sending the data to the queue, because there was no free space. In this case, this OS message queue put function is returning OS error timeout, which means that the timeout elapsed without being successful in sending the data to the queue. It is important to monitor the output of this function once we are using it within the task. In case we specify OS wait forever as this timeout, the task will be blocked till there will be a free space in the queue to send a new data. So it can be used to really block the task till the queue will have the free space to send the data. So it's really like a semaphore with possibility to send something afterwards. If there is a free space in the queue, the sender will continue execution. So the next instruction will be executed just after it will send the data to the queue. So it will not wait the setable time, this timeout, but it will continue just after sending data to the queue. This is an important message in terms of calculating the timeout, the timings within the tasks. Concerning the receiver, a receiver to get the data from the queue is calling OS message queue get function, and if the queue is empty, receiver task will be blocked for again, setable time, then it can continue, of course without the data reception. In this case, there will be this return value OS timeout, please for more details you can go to specification of the type OS status underscore t which is used here. In case we'll specify it as a timeout OS wait forever, the receiver task will be blocked till there would be any new data within the queue. So again, it can be used to block the task till the data will come to the queue. If the data are available within the queue that can be read by the task, the task will continue just after the data reception. So again, it will not wait till the timeout will elapsed, but just after the data reception. And then important message is that the scheduler is responsible to move the task from ready to blocked state and vice versa, both cases just described. Before we will go with the code processing, let's discuss what we would like to have within our application. Because both tasks, sender1, sender2 and receiver as well have the same priority, receiver will get data from the queue after both tasks put the data into it. So we can monitor what would happen if the queue would be full, what would be the side effect, how it will be visible. Here on the screen we can see such a situation. So at the beginning, receiver would like to have read something from the queue, but the queue is empty. So receiver is blocked, is waiting for the new data and scheduler is switching the context to the next task, which can be sender1, which is as follow the ready list. And sender1 is sending the data to the queue. And then after it will finish its job, the scheduler is switching it to the next task from the ready list. So the last task, which has been not yet executed from the ready list with the same priority is sender2. So again, sender2 is sending next data to the queue. So after this, we've got two items within the queue, then there is let's say the time for receiver. So receiver can accept within its time slot and accept one item from the queue. So after this queue will have still one component. And then again, we've got the time for both senders, sender1 and sender2. So at the end, we'll have three items in the queue. And then after receiver action, we will have one component less. And in a few iterations like this, we'll have the situation when the queue will be full. And the sender would be blocked because there would be no free space to put more data. So in this case, it will be put in the blocked states. And it would need to wait till receiver will accept some data from the queue. This is how it will work. Let's check, let's verify whether it will be exactly like we see on the screen. Let's do some practice with queue where there are two senders and one receiver. We can reuse previous lab. We'll start with stm32cubemix or stm32cubeide, then free artist configuration, tasks and queue stub. Let's create two sending tasks, sender1 and sender2 and one receiver task with the same priorities like on the picture. We will use one queue with eight elements, eight bit long. After adding of those components, please generate the code and open main.cfile. Within main.cfile, we need to implement ng functions for sender's tasks. Within start sender1 function, we will define local 8-bit variable x set to 1. Then with an endless loop, we will send small s via swo interface using task underscore action function. After this, we will put x variable to the queue with 200 milliseconds timeout. And in the end, we will put sender1 task into blocked state for two seconds using osdli function. Similar operations will implement within start sender2 function with different value of x variable, this time we will set it to 2. And then we will send big s over swo interface instead of small 1 within task underscore action function just to distinguish in the final effect operations from sender1 and sender2. Then we need to implement our start receiver function. We will implement local 8-bit variable res set to 0. With an endless loop, we will send big r over swo interface using task underscore action function. After this, in case of successful reception data from the queue, we will send received character over swo using again task underscore action function. We will try to receive data from the queue using osmessageqget() function with 4 seconds timeout. Then we will send our receiver task to blocked state for two seconds using osdli function. After all of those code operations, please build a project, start the bug session, open switm console and start the application. We should receive the results like this one on the screen. The beginning sender1 is sending big s, then sender1 is sending small s and then receiver is sending its big r and its next iterations it is receiving both elements from the queue and displaying them as 2r and 1r. What would happen if receiver will higher priority than senders? Let's analyze the situation on below picture. Receiver is executed first as highest priority task. It is blocked as queue is empty, then sender1 is sending some data to the queue. This action unblocks receiver task. Receiver task continues its execution as it is the task of the highest priority and in its next iteration of the endless loop it is blocked again by waiting for some data on the queue, which is again empty. After this, sender2 is selected by the scheduler. This task is sending some data to the queue. Just after this, receiver is woken up again by the scheduler, is moved from the blocked to a run state. It is reading data from the queue and again it is sent to blocked state by waiting for next data on the queue. And the situation repeats, so sender1 is sending some data to the queue, it is waking up the receiver, then receiver is sent to blocked state again waiting for new data, then sender1 is selected by scheduler and it's sending some data to the queue and so on and so forth. Let's perform simple example to test this situation. Let's continue with previous lab doing only one small modification. In our case, receiver will have a higher priority than both senders, so let's start from stm32cubemix or stm32cube IDE. Within free RTS configuration, please select tasks and queues tab. And then please change receiver task priority from OS priority normal, which is selected for both senders, to OS priority above normal. So in our case, receiver will have a higher priority than both senders. After this, please build a code, start a debug session and verify whether behavior is in line with our expectations. This is our result. Receiver is executed first as highest priority task. It managed to send big R and then it is blocked by waiting on the queue. Then sender1 is sending some data there. We can notice it by small S on SWO console. This action unblocks receiver task, which is displaying this message, it is one. It continues its execution as it is the task for the highest priority. When it's next iteration, it managed to display R again and then it is blocked by waiting on the queue. After this, sender2 is selected by scheduler. It is sending two to the queue and big S over SWO. Just after this, receiver is woken up. It is sending two R over SWO and it's blocked again waiting for next data on the queue. Let's consider the situation where we have single sender and two receivers. We should remember that the message from the queue is taken by the task with highest priority. In case of equal priorities, the task which is waiting longer time will be selected by the scheduler, thus it is not deterministic. Even if higher priority task is in blocked state, waiting for the access to the queue, it will be woken up immediately by the kernel in case queue will contain a new data. Only in a case higher priority task is in the suspend mode, it will be not taken into consideration by the scheduler. Thank you for watching this video.