Queue in RT-Thread RTOS – RT-Thread Tutorial Part 7

This article is a continuation of the  Series on RT-Thread STM32 Tutorials and carries the discussion on RT-Thread RTOS and implementation with STM32. The aim of this series is to provide easy and practical examples that anyone can understand. In our last post, we have seen Mailbox in the RT-Thread RTOS. In this post, we will see the Message Queue in RT-Thread RTOS.

You can see the video explanation of Getting started with the RT-Thread RTOS.

Prerequisites

This is the continuation of the below tutorials. If you don’t read it, please read that also before this.

Tools and Components Required

Inter-thread Communication in RT-Thread RTOS

If we are working in a multithreaded environment, we need to send data from one thread to another thread. There are many ways to do that. Normally we use global variables or some memory segment for that purpose. Sometimes it is hard to use global data. Because it is difficult to keep track of the messages. To make our lives easier, RTOSs are will support a few inter-thread communication methods. RT-Thread RTOS supports the below inter-thread communication methods.

Message Queue in RT-Thread RTOS – RT-Thread Tutorial Part 7

Message Queue

Message Queuing is another commonly used inter-thread communication method, which is an extension of the mailbox. A queue is a FIFO (First In First Out) type buffer where data is written to the end (tail) of the queue and removed from the front (head) of the queue. A queue can either hold the data or a pointer to the data. A message queue can receive messages with unfixed lengths from threads or ISR and cache messages in their own memory space. So, the thread can put one or many messages to the queue.

Management of Message Queue

In RT-Thread RTOS, the queue supports the below operations.

Creating/initiating a queue

To dynamically create a message queue object, call the following function interface:

rt_mq_t rt_mq_create(const char* name, rt_size_t msg_size,
                     rt_size_t max_msgs, rt_uint8_t flag);

The size of this memory = [message size + message header (for linked list connection) Size] X the number of messages in the message queue.

Input parameters and return values for rt_mq_create()

Parameters Description
name The name of the message queue
msg_size The maximum length of a message in the message queue, in bytes
max_msgs The number of messages in the message queue
flag The waiting method took by the message queue, which can take the following values: RT_IPC_FLAG_FIFO or RT_IPC_FLAG_PRIO
Return ——
RT_EOK Sent successfully
The handle of the message queue object Successful
RT_NULL Fail

You can use the below API to create the Static message queue.

rt_err_t rt_mq_init(rt_mq_t mq, const char* name,
                    void *msgpool, rt_size_t msg_size,
                    rt_size_t pool_size, rt_uint8_t flag);

Input parameters and return values of rt_mq_init()

Parameters Description
mq The handle of the message queue object
name The name of the message queue
msgpool Pointer pointing to the buffer storing the messages
msg_size The maximum length of a message in the message queue, in bytes
pool_size The buffer size for storing messages
flag The waiting method is taken by the message queue, which can take the following values: RT_IPC_FLAG_FIFO or RT_IPC_FLAG_PRIO
Return ——
RT_EOK Successful

Deleting/detaching a queue

You can use the below API to delete the dynamically created message queue (message queue which has been created using the rt_mq_create()).

rt_err_t rt_mq_delete(rt_mq_t mq);

If you have used a static message queue (message queue which has been initialized using rt_mq_init() ), then you can use the below API to detach the message queue.

rt_err_t rt_mq_detach(rt_mq_t mq);

When deleting/detaching a message queue, if a thread is suspended on the message queue object, the kernel first wakes up all threads suspended on the queue (the thread return value is –RT_ERROR), then releases the memory used by the queue and finally deletes/detaches the queue object.

Sending messages to the queue

We can send messages in three ways.

Send a message without waiting

The below API is used to send a message without waiting.

rt_err_t rt_mq_send (rt_mq_t mq, void* buffer, rt_size_t size);

Input parameters and return values of rt_mq_send()

Parameter Description
mq The handle of the message queue object
buffer Message content
size Message size
Return ——
RT_EOK Successful
-RT_EFULL A message queue is full
-RT_ERROR Failed, indicating that the length of the sent message is greater than the maximum length of the message in the message queue.

If the queue is full, then this function will return an error code (-RT_EFULL). So, we can use this function in the thread as well as in the ISR.

Send a message with waiting

Users can also send messages to specified message queues through the following function interface:

rt_err_t rt_mq_send_wait(rt_mq_t mq,
                    const void *buffer,
                    rt_size_t size,
                    rt_int32_t timeout);

Input parameters and return values of rt_mb_send_wait()

Parameter Description
mq The handle of the message queue object
buffer Message content
size Message size
timeout Timeout
Return ——
RT_EOK Successful
-RT_EFULL A message queue is full
-RT_ERROR Failed, indicating that the length of the sent message is greater than the maximum length of the message in the message queue.

If the queue is full, then this function will wait based on the timeout value. If the timeout expires, then it will return -RT_EFULL. So, we cannot use this function in the ISR.

Send an emergency message

We know that Queue is a FIFO. But we can put the message also in the front. So that, the message will be delivered ASAP without waiting in the back. The below function is used to put the message into the front.

rt_err_t rt_mq_urgent(rt_mq_t mq, void* buffer, rt_size_t size);

The process of sending an emergency message is almost the same as sending a message. The only difference is that when an emergency message is sent, the message block taken from the idle message list is not put at the end of the message queue, but at the head of the queue.

Input parameters and return values of rt_mq_urgent()

Parameters Description
mq The handle of the message queue object
buffer Message content
size Message size
Return ——
RT_EOK Successful
-RT_EFULL A message queue is full
-RT_ERROR Fail

Receive the message from the queue

To receive messages from the queue, we can use the below function. If the queue is empty, it will wait till the timeout. If the timeout expires, then it will return an error.

rt_err_t rt_mq_recv (rt_mq_t mq, void* buffer,
                     rt_size_t size, rt_int32_t timeout);

Input parameters and return values of rt_mq_recv()

Parameters Description
mq The handle of the message queue object
buffer Message content
size Message size
timeout Specified timeout
Return ——
RT_EOK Received successfully
-RT_ETIMEOUT Timeout
-RT_ERROR Fail, return error

Message Queue in RT-Thread Example

In the below example, we have created the two threads. Thread 1 is incrementing the count and sending the count value to the queue. Thread 2 will be waiting for the messages in the queue. Once the message is posted by thread 1, then thread 2 will wake up and read the data, and prints it.

Source code

You can get this entire project’s source code from GitHub.

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG

#include <rtdbg.h>
#include <drv_common.h>
#include <rtdevice.h>

/* Message queue control block */
static struct rt_messagequeue *mq;

static rt_thread_t threadId1 = RT_NULL;
static rt_thread_t threadId2 = RT_NULL;

/* Thread 1 */
static void thread1_function(void *parameter)
{
    uint32_t count = 0;
    while (1)
    {
        count++;
        LOG_D("Thread 1: count = %d\n", count);
        rt_mq_send(mq, (void*)&count, sizeof(uint32_t));
        rt_thread_mdelay(1000);
    }
}

/* Thread 2 */
static void thread2_function(void *parameter)
{
    uint32_t received_message = 0;
    while (1)
    {
        /* Receive message from the queue */
        if (rt_mq_recv(mq, &received_message, sizeof(uint32_t), RT_WAITING_FOREVER) == RT_EOK)
        {
            LOG_D("Thread2: Got a message, the message:%u\n", received_message);
        }
    }
}

int main(void)
{
    /* create queue object */
    mq = rt_mq_create("etx_mq", sizeof(uint32_t), 10, RT_IPC_FLAG_FIFO);
    if( mq  == RT_NULL )
    {
        LOG_D("Queue init failed.\n");
        return -1;
    }

    /* Create thread 1 */
    threadId1 = rt_thread_create("thread1_fn",        //Name
                                  thread1_function,   //Function address
                                  RT_NULL,            //Thread function parameter
                                  1024,               //Stack Size
                                  1,                  //Thread priority
                                  2000);              //Time slice in ticks

    /* Create thread 2 */
    threadId2 = rt_thread_create("thread2_fn",        //Name
                                  thread2_function,   //Function address
                                  RT_NULL,            //Thread function parameter
                                  1024,               //Stack Size
                                  1,                  //Thread priority
                                  2000);              //Time slice in ticks

    /* Start both threads */
    rt_thread_startup(threadId1);
    rt_thread_startup(threadId2);

    while(1);

    return RT_EOK;
}

Queue in RT-Thread – Output

 \ | /
- RT -     Thread Operating System
 / | \     4.1.1 build Mar  8 2023 09:55:56
 2006 - 2022 Copyright by RT-Thread team
←[0m[D/main] Thread 1: count = 1
←[0m
←[0m[D/main] Thread2: Got a message, the message:1
←[0m
←[0m[D/main] Thread 1: count = 2
←[0m
←[0m[D/main] Thread2: Got a message, the message:2
←[0m
←[0m[D/main] Thread 1: count = 3
←[0m
←[0m[D/main] Thread2: Got a message, the message:3
←[0m
←[0m[D/main] Thread 1: count = 4
←[0m
←[0m[D/main] Thread2: Got a message, the message:4
←[0m
←[0m[D/main] Thread 1: count = 5
←[0m
←[0m[D/main] Thread2: Got a message, the message:5
←[0m
←[0m[D/main] Thread 1: count = 6
←[0m
←[0m[D/main] Thread2: Got a message, the message:6
←[0m
←[0m[D/main] Thread 1: count = 7
←[0m
←[0m[D/main] Thread2: Got a message, the message:7
←[0m

In our next tutorial, we will see the signals in RT-Thread RTOS.

You can also read the below tutorials.

Linux Device Driver Tutorials C Programming Tutorials
FreeRTOS Tutorials NuttX RTOS Tutorials
RTX RTOS Tutorials Interrupts Basics
I2C Protocol – Part 1 (Basics) I2C Protocol – Part 2 (Advanced Topics)
STM32 Tutorials LPC2148 (ARM7) Tutorials
PIC16F877A Tutorials 8051 Tutorials
Unit Testing in C Tutorials ESP32-IDF Tutorials
Raspberry Pi Tutorials Embedded Interview Topics
Reset Sequence in ARM Cortex-M4 BLE Basics
VIC and NVIC in ARM SPI – Serial Peripheral Interface Protocol
STM32F7 Bootloader Tutorials Raspberry PI Pico Tutorials
STM32F103 Bootloader Tutorials RT-Thread RTOS Tutorials
Zephyr RTOS Tutorials – STM32 Zephyr RTOS Tutorials – ESP32
AUTOSAR Tutorials UDS Protocol Tutorials
Product Reviews STM32 MikroC Bootloader Tutorial
VHDL Tutorials

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Table of Contents