embeddedmessage-queuefifortosucos

Message queue in uC/OS-II is not FIFO order?


I'm using kit De10-Nano which has successfully ported uC/OS-II as in the example on the Weston Embedded website. Currently, I'm having a problem with message queue API of the OS.

My program contains two tasks: producer task (priority 5) and consumer task (priority 4). My purpose is that the producer task would send the message to the consumer task via a message queue. In the first time I've tried, the producer task is slower than the consumer task (producer task is delayed for 100ms and consumer task is delayed for 10ms) and the message queu e works fine as every time producer task sends a message (using OSQPost), the consumer task receives it (using OSQPend). However, when I change the time slice for both task to make the consumer task runs slower than the producer task, I've expected that the consumer task can extract data from the message queue in the FIFO order. However, the data extracted by the consumer task is not in that order.

Here is my code:

/* Includes ------------------------------------------------------------------*/
/* Standard C/C++ Library Includes */
#include <stdio.h>
#include <stdint.h>
/* User Library Includes */

/* Altera's Library Includes */

/* uC/OS-II's Library Includes */
extern "C"
{
#include "includes.h"
}
/* End of Includes ------------------------------------------------------------------*/

/* Private defines ---------------------------------------------------------*/
#define PRODUCER_TASK_STK_SIZE          (1024)
#define CONSUMER_TASK_STK_SIZE          (1024)

#define PRODUCER_TASK_PRIO              (5)
#define CONSUMER_TASK_PRIO              (4)

#define MSG_QUEUE_SIZE                  (30)
/* USER CODE BEGIN PD */
static OS_STK       ProducerTaskStk[PRODUCER_TASK_STK_SIZE];
static OS_STK       ConsumerTaskStk[CONSUMER_TASK_STK_SIZE];
void*               myMsgQueue[MSG_QUEUE_SIZE];
static OS_EVENT*    msgQueueHandler;
static uint32_t     myProducerBuffer = 0;
static uint32_t     myConsumerBuffer = 0;
static uint8_t      errorCode;
static OS_Q_DATA    queue_data;
/* USER CODE END PD */

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
static void ProducerTask    (void  *p_arg);
static void ConsumerTask    (void  *p_arg);
/* USER CODE END PFP */

static void ProducerTask (void  *p_arg)
{
    while(1)
    {
        ++myProducerBuffer;
        printf("Producer sent value: %d\n", myProducerBuffer);
        if(OSQPost(msgQueueHandler, (void*)&myProducerBuffer) != OS_ERR_NONE)
        {
            printf("Producer sent failed\n");
        }
        else
        {
            OSQQuery(msgQueueHandler, &queue_data);
            printf("Current queue size in producer: %d\n", queue_data.OSNMsgs);
        }
        OSTimeDlyHMSM(0u,0u,0u,10u);
    }
}

static void ConsumerTask  (void  *p_arg)
{
    uint32_t* pConsumerBuffer;
    while(1)
    {
        pConsumerBuffer = (uint32_t*)OSQPend(msgQueueHandler, 0, &errorCode);
        myConsumerBuffer = *pConsumerBuffer;
        printf("Consumer get value: %d\n", myConsumerBuffer);
        OSQQuery(msgQueueHandler, &queue_data);
        printf("Current queue size in consumer: %d\n", queue_data.OSNMsgs);

        OSTimeDlyHMSM(0u,0u,0u,100u);
    }
}

int main()
{
    OSInit();

    msgQueueHandler = OSQCreate(&myMsgQueue[0],MSG_QUEUE_SIZE);

    OSTaskCreateExt(ProducerTask,                               /* Create the producer task                              */
                    0,
                    &ProducerTaskStk[PRODUCER_TASK_STK_SIZE - 1u],
                    PRODUCER_TASK_PRIO,
                    PRODUCER_TASK_PRIO,
                    &ProducerTaskStk[0u],
                    PRODUCER_TASK_STK_SIZE,
                    0u,
                    (OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));

    OSTaskCreateExt(ConsumerTask,                               /* Create the consumer task                              */
                    0,
                    &ConsumerTaskStk[CONSUMER_TASK_STK_SIZE - 1u],
                    CONSUMER_TASK_PRIO,
                    CONSUMER_TASK_PRIO,
                    &ConsumerTaskStk[0u],
                    CONSUMER_TASK_STK_SIZE,
                    0u,
                    (OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));

    OSStart();

    while(1); /* Should never get here. */

    return -1;
}

And here is my result: enter image description here

At first, producer sends 1 and consumer receives 1. And then, the consumer is delayed for 100ms and producer sends message from 2 to 10 to the message queue during this time. The consumer then extracts from the message queue and get value of 10 instead of 2. So I'm assuming that the message queue is not in FIFO order. Is there anything I've done wrong ? If not, why the message queue does not behave as I've expected ?


Solution

  • The uC/OS-II Message Queue is FIFO when you use OSQPost(). You have a different problem.

    You're mistake is expecting that the Queue stores a copy of the message when the Queue actually stores a pointer to the message. Your code repeatedly posts the same pointer to the myProducerBuffer variable and then changes the value of the underlying variable. Your queue does not contain a copy of all the different values. Your queue contains multiple pointers to the same value. Each time you increment myProducerBuffer you are changing the value pointed to by all the pointers in the queue.

    If you want to use a Queue like this you need to allocate the messages separately so each message has a unique address while it's in use by the Queue.