Understanding Queue Sets (xQueueSelectFromSet)

rekharamapai wrote on Wednesday, July 25, 2018:

I am trying to understand the Queue Sets, in particular how xQueueSelectFromSet and xQueueReceive work. Consider the following code, in which the main creates a queue, one sender task and two receiver tasks. The queue is added to a queue set. vReceiverTask1 uses xQueueSelectFromSet and then xQueueReceive to read data from queue while vReceiverTask2 directly reads from queue.
Can vReceiverTask2 create problem for vReceiverTask1 while it reads data from queue?
My actual DOUBT is noted in the code below for vReceiverTask1.

/* The queue is added to a queue set. */
static QueueHandle_t xQueue = NULL;

/* This is the queue set to which the queue is added. */
static QueueSetHandle_t xQueueSet = NULL;

int main( void )
{
/* Create the queue, which send character pointers.
The priority of the sending task is more than the priority of the receiving task. */
xQueue = xQueueCreate( 1, sizeof( char * ) );

/* Create the queue set. The queue will be added to the set. */
xQueueSet = xQueueCreateSet( 1 );

/* Add the queue to the set. */
xQueueAddToSet( xQueue, xQueueSet );

/* Create the task that send to the queue. */
xTaskCreate( vSenderTask, "Sender", 1000, NULL, 2, NULL );

/* Create the tasks that read from the queue set and the queue directly. */
xTaskCreate( vReceiverTask1, "Receiver1", 1000, NULL, 1, NULL );	
xTaskCreate( vReceiverTask2, "Receiver2", 1000, NULL, 1, NULL );

/* Start the scheduler so the created tasks start executing. */
vTaskStartScheduler();

for( ;; );

return 0;

}
/-----------------------------------------------------------/

void vSenderTask( void *pvParameters )
{
const TickType_t xBlockTime = pdMS_TO_TICKS( 20 );
const char * const pcMessage = “Message from vSenderTask\r\n”;

for( ;; )
{
    /* Send this task's string to xQueue. */
    xQueueSend( xQueue, &pcMessage, 5 );

    /* Block for 20ms. */
    vTaskDelay( xBlockTime );
}

}

/-----------------------------------------------------------/

void vReceiverTask1( void pvParameters )
/
The task that reads using the queue set */
{
const TickType_t xBlockTime = pdMS_TO_TICKS( 10 );
QueueHandle_t xQueueThatContainsData;
char *pcReceivedString;

for( ;; )
{
/* DOUBT: Does a call to xQueueSelectFromSet guarantee availability of data in the returned queue xQueueThatContainsData? */
    xQueueThatContainsData = ( QueueHandle_t ) xQueueSelectFromSet(xQueueSet, portMAX_DELAY );

/* DOUBT: If a task switch occurs to vReceiverTask2 task here, */
/* how the following xQueueReceive read the expected data? */
    xQueueReceive( xQueueThatContainsData, &pcReceivedString, xBlockTime );

    /* Process the string received from the queue. */

    /* Block for 10ms. */
    vTaskDelay( xBlockTime );
 }

}

void vReceiverTask2( void pvParameters )
/
The task that reads directly from the queue */
{
const TickType_t xBlockTime = pdMS_TO_TICKS( 10 );
char *pcReceivedString;

for( ;; )
{        
    xQueueReceive( xQueue, &pcReceivedString, xBlockTime );

    /* Process the string received from the queue. */

    /* Block for 10ms. */
    vTaskDelay( xBlockTime );
}

}

I found the following Note in the documentation.
“Do not read data from a queue or semaphore that is a member of a set unless the handle of the queue or semaphore has first been returned from a call to xQueueSelectFromSet().”

Does this mean the onus is on the developer that she has to read from a queue, which belongs to a queue set, only after getting the handle from xQueueSelectFromSet?

Thanks.

rtel wrote on Wednesday, July 25, 2018:

Not read through all the code but just from your description: If you
are using a queue that is in a set then you can only read from the queue
after its handle has been returned from the set. In addition, if its
handle is returned from the set then you must read from the queue.

rekharamapai wrote on Thursday, July 26, 2018:

Thanks Barry for the response.

Just to seal it once and for all,
So does it mean that the developer has to make sure that the restriction you mentioned is enforced or will any kernel API enforce this?

Thanks.

rtel wrote on Thursday, July 26, 2018:

The developer does.

rekharamapai wrote on Thursday, July 26, 2018:

Ok. Got it.