Failed to understand the pointers movement in Queue related operations

luauto wrote on Wednesday, January 27, 2016:

Hi all,
When I trying to clarify the pointers movement in queue operations, I found that I fell in confusion.
Below is my current understanding about queue operation, please point out my mis-undestanding points.

  1. First call xQueueGenericCreate() API to create a new Queue, the API will set pcHead pointer and then call xQueueGenericReset() to set the pcTail, pcReadFrom and pcWriteTo pointers, etc.
  2. After step 1), there will be pcHead == pcWriteTo, pcReadFrom + uxItemSize == pcTail;
  3. Then, I call xQueueGenericSend() to send one item to the BACK of the queue, it will call prvCopyDataToQueue() API. In prvCopyDataToQueue(), the pointer pcWriteTo is incremented.
  4. Finally, I want to read the stored item using API xQueueGenericReceive(). In this API, it will call prvCopyDataFromQueue() to retrieve the stored item. But it only increments pointer pcReadFrom and read its pointed data to buffer.

My questions are below:
(1) Which position is the Back of the Queue? Is it pointed by pcTail?
(2) Since when sending items to the Back of the Queue, it only changes pointer pcWriteTo; However, when I want to receive the stored items, it changes pointer pcReadFrom, but seems the pcReadFrom never changes after calling xQueueGenericReset() and maybe far from the position of the stored item.

I think my understanding is wrong, but I still cannot figure out the root cause. I’m reading the code of V8.2.1;

Hope someone can help me about the confusion, thanks in advance!
Best regards!

rtel wrote on Wednesday, January 27, 2016:

This is all internal implementation detail - I assume you are only looking at it out of interest.

As far as I can see the write to pointer points to the next space to be written to, so gets incremented after it has been written, while the read from pointer points to the last item read, so gets incremented before an item is read from the queue.

luauto wrote on Thursday, January 28, 2016:

Hi,
yes, I’m reading the code for interest, but I just cannot understand the internal mechanism.
Could you please point out the code how the pcReadFrom changes to point to the last item to read? Seems I didn’t see the code specify it.

heinbali01 wrote on Thursday, January 28, 2016:

Have a look at xQueueGenericReset() :

    pxQueue->pcWriteTo = pxQueue->pcHead;
    pxQueue->u.pcReadFrom = pxQueue->pcHead +
        ( ( pxQueue->uxLength - ( UBaseType_t ) 1U ) * pxQueue->uxItemSize );

When the queue is created, the pcReadFrom member will point to the last item in the queue (to N-1)

After that the code will:

    read from ++pcReadFrom  ( pre-increment )
    write to pcWriteTo++ ( post increment )

Does that make it clear?

luauto wrote on Friday, January 29, 2016:

Hi Hein,
Thank you for your reply.
Let’s specify a model to illustrate it.

  1. Say, I will create a queue with uxLength == 10, which will hold item 1 to 10. So, after calling xQueueGenericCreate() API, the pcReadFrom will point to item 9, pcWriteTo will point to item 1, but remember the queue has no data now.
  2. Then, I call xQueueGenericSend() to send one item to the BACK of the queue, it will increment the pointer pcWriteTo with one item step, but won’t change pcReadFrom, right?
  3. Finally, I call xQueueGenericReceive(), it only increments pointer pcReadFrom and read its pointed data to buffer. But you know, now pcReadFrom is pointing to item 9, with no valid data, the valid data is at item 1 position.

Above is my confusion, am I describe it clearly to you?

rtel wrote on Friday, January 29, 2016:

I think this has been described twice already, you can see in the source
code how this works, and if it is not clear from the source code you can
step through the source code in the debugger to view what is happening:

the pcReadFrom will point to item 9

Yes.

it only increments pointer pcReadFrom

Yes.

But you know, now pcReadFrom is pointing to item 9

No. If it starts pointing at 9, and is then incremented, it is no
longer pointing at item 9.

heinbali01 wrote on Friday, January 29, 2016:

Not sure if this examples helps:

queueSEND_TO_BACK  : the normal way, using a queue as a FIFO
queueSEND_TO_FRONT : add an item that will be read firstly (more like a STACK)

This queue has 10 items. Their positions are numbered 0 to 9 (not 1 to 10).

	pcWriteTo		|	 pcReadFrom

Initial situation:

	0				|	 9

queueSEND_TO_BACK :

	write at 0		|	 9
	1				|

queueSEND_TO_BACK :

	write at 1		|	 9
	2				|

queueSEND_TO_FRONT :

	2				|	 write at 9
                                     |	 9 -> 8

Read all 3 times :

	2				|	 8 -> 9 read from 9
	2				|	 9 -> 0 read from 0
	2				|	 0 -> 1 read from 1

luauto wrote on Friday, January 29, 2016:

Hi Hein,
Thank you for your detailed explanation and patience. I have noticed my wrong point.

Last question, please.
About the concept of “Front” and “Back”. The “Front” means the pcTail side, and the “Back” means the “pcHead” side, am I right?

Best regards!

heinbali01 wrote on Friday, January 29, 2016:

The “Front” means the pcTail side, and the “Back” means the “pcHead” side, am I right?

No, not necessarily. pcHead and pcTail are a kind of const pointers that define the beginning and the end of the queue space.
Items are written at the position pcWriteTo or pcReadFrom, depending on the value of xCopyPosition (resp BACK or FRONT).

As I said, adding items to the BACK is the usual way. That works like a fifo. Add items a-b-c, and you can read them back in the same order a-b-c.

When you add items a-b-c at with SEND_TO_FRONT, you will read back c-b-a. The last item comes out first.

In some situations, a mixture of SEND_TO_BACK and SEND_TO_FRONT can be very useful: the first one is used for all normal messages, the latter is used to send an emergency message, which will be treated first.

Regards.