Hypothetical scenario 1: There is a queue on which 1 task is blocked waiting for data to arrive. Data arrives and the task unblocks. The task was just wanting to peek the data (not remove it) so takes a copy of the data and leaves the queue peek function. Now presumably it will perform some action, then later go back to the queue again where it will immediately find the data it just peeked. I think this behaviour is logical and ok, and is how the GenQTest.c demo tasks work. Hypothetical scenario 2: There is a queue on which 2 tasks are blocked waiting for data to arrive. Both tasks are the same priority. Data arrives and unblocks one of the tasks, this task was just peeking so takes a copy of the data and leaves. Now what should happen? There is another task blocked on the queue waiting for data, and there is already data in the queue – should this second task be unblocked after the first task has peeked the data? What would be the logical thing to do, or how would you expect this scenario to work? Hypothetical scenario 3: Same as 2, but this time the two tasks that are blocked on the queue are of different priority. The higher priority task wakes and peeks the data – should the second task then be unblocked because there is data in the queue that was not removed? The second task is of lower priority so will not execute until the first task blocks again (it is ok if the first task removes the data before the second task executes, FreeRTOS.org already handles this situation). Provided the behaviour is documented, does it matter which implementation is chosen (wake the second task, not wake the second task)? Maybe it should be a compile time option – but this would add complexity and more preprocessor macros, plus more code to test. Maybe there should be a rule that tasks can not block on a queue when they are just peeking? Regards.
I think that once a task peeks at a queue, it shouldn’t reawaken until new data is posted. Seems to me if a task just peeks the data but doesn’t use it, it means it didn’t want the data. Here are the three examples posted by Richard using my No Reawaken criteria: Scenario 1 (amplified): The task is receiving a packet from the outside world and is waiting on the End-of-Packet character. The task peeks the queue, finds that it isn’t the right character, and goes back to sleep. When the End-of-Packet character finally comes in, it reads the entire packet from the queue and stores it. Sure there are other, maybe better ways of doing this but this is just an example. Scenario 2: Task 1 wakes, peeks at the data, and doesn’t want it. It goes back to sleep. Task 2 wakes up, gets the data from the queue, and goes back to sleep. If task 2 woke first, it would get the data from the queue and task 1 would never wake (it didn’t want the data anyway). If neither task wants the data, they both go back to sleep until more data comes in. Scenario 3: Task 1 (high priority) wakes and peeks the queue. It doesn’t want it so it goes back to sleep. Task 2 wakes and gets the data. If task 1 got the data, task 2 would never wake up. Scenarios 2 and 3 assume that only one task can use the data. If both tasks need the data then perhaps one task should block on the queue and then send the data to the second task. It should be okay for a task to block on a queue if just peeking, as shown by the scenarios above.
> Scenario 1 (amplified): > > The task is receiving a packet from the outside world and is > waiting on the > End-of-Packet character. The task peeks the queue, finds > that it isn’t the > right character, and goes back to sleep. When the > End-of-Packet character finally > comes in, it reads the entire packet from the queue and > stores it. Sure there > are other, maybe better ways of doing this but this is just > an example. But peeking the queue will return the first item placed into the queue, right? Not the last. Unless all items are placed using QueueSendToFront().
Yes. Either use xQueueSendToFront or use an array index counter and save the queue backwards. I didn’t bother mentioning it because it wasn’t really relevant to the post.
jorick23 – with respect to your feedback. I agree in an ideal case a task would peek at the queue, then have the ability to go back to sleep until more data arrives. I’m not sure if this is possible though. Say the task unblocks, peeks the data, decides it does not want it, then goes back to block on the queue. The queue data was left in the queue but the task does not know if it is still there or not – another task may have executed in between and removed it. The task must leave the queue function in order to decide whether or not it wants the data, then re-enter the function to block again. Unless this is all done in a critical section it does not know what the queue state is on the second entry. The documentation on this new functionality is going to have to be very explicit to ensure people know the ins and outs of its use. Regards.
I’m thinking how I would use peek. I think that I would use it to have several tasks blocked on the same queue. I would have all the tasks receiving data only use peek to get the data. And the lowest priority actually remove the data. (or even a dummy reader in the idle task clean out the queues) This would work well if multiple tasks needed the same data. If this is how I used it then Hypothetical scenario 3 would be the most useful. Another possible, but similar situation would also be several tasks blocked on the same queue. but instead of all of them only using peek to get the data, peek would only be used to block and see if it wants the data, and xQueueReceive would actually be used to get the data. This would be used if data is only useful for one task, but you don’t know who actually needs it. Again though the lowest priority task needs to clear out the queue no matter what. again this fits Hypothetical scenario 3 One issue with this setup is what to do with a task of a higher priority where it peeks and doesn’t want that data. How do you block again on the same queue, yet still have lower priority tasks get the queue. Would you need to implement a queue skip function? Or would calling task yield be good enough to let a lower priority task get to the data? Or would calling peek again allow a lower priority task to check? if peek was able to return the number of messages stored in the queue, rather than true false, then I can come up with some more situations where Hypothetical scenario 2 would be useful. For example waiting for several chunks of messages to build up before processing. If only true false is returned, I don’t see how useful it would be. maybe I’m missing a situation. -Sashi
in responce to >Scenario 1 (amplified): >The task is receiving a packet from the outside world and is waiting on the End-of-Packet character. The task peeks the queue, finds that it isn’t the >right character, and goes back to sleep. When the End-of-Packet character finally comes in, it reads the entire packet from the queue and stores it. >Sure there are other, maybe better ways of doing this but this is just an example. I don’t think you would be able to do this unless you had PeekTailofQueue. or something like that. I guess you could make peekHead and peekTail.
Hi I would like to give an example I am handling now that may be solved using the Queue peek there is ADC task reading at high priority every 1msec then there are several diffrent task in several lower priorety using that data (at different rate) right now each reading task get it own Queue from the ADC task maybe using the Queue peek can solved it. what do you think about this - the Queue is fifo and defined as peek queue (not task peek the queue but the entire queue is in peek method) - only the writer can remove data from the queue (fifo) and add data (cyclic) - several reader have pointer to the data queue and each read increase his pointer to next place (cyclic) - if after increasing reader pointer it equal writer pointer, the reader is blocked waiting to new data - if after increasing writer pointer it equal reader pointer, the specific reader is indicated that it missed data (missed data counter) that way instead of task peek queue, the entire queue is defined as peek queue high priority task always read data but don’t clear it, so low priority task can read it at there time the longer the queue the biggest the chance that low priority will be able to read the entire data. must to admit it is my first time programming RTOS so I may be totally wrong thanks
I’m not so keen on this way around. It is not as flexible as having a queue that you can choose to either peek from or receive from.
Thanks for all your thoughts. I am going to update so that when you have peeked from a queue but leave data in the queue the next task that is blocked on the same queue will be unblocked. If this task is of lower priority it will not actually run until the originally unblocked task blocks again – at which time, if the queue has been emptied again, it will simply automatically return to block on the queue for the remains of its block period as if nothing had happened. This all happens internally to FreeRTOS.org. This seems to be the most flexible way. The application writer will have to be aware of the implications of peeking a queue. Without this change it would be possible for tasks to be blocked on a queue even when there was data available, which does not seem right. I think this is just a 1 line change, but also need to update the new demo/test task to test the behaviour. I might not get this done until this evening. It is in fact (I think) rare in small embedded systems to have more than one task read from the same queue in any case, whereas the opposite is not true as it is common to have multiple tasks write to the same queue. At least this is the case in the software that I write. Regards.
This is in SVN now. As mentioned it is only a one line change to queue.c. In addition I have added the file Demo/Common/Minimal/QPeek.c to test this behaviour. The OpenWatcom demo project has been updated to include the new QPeek demo/test tasks. I am currently running this on the PC port and a Cortex-M3 port. Regards.
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.