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 Mutex and Event in the RT-Thread RTOS. In this post, we will see the Inter-thread communication methods 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.
- RT-Thread RTOS Introduction
- Getting started with RT-Thread RTOS – Part 1
- Thread management of RT-Thread RTOS – Part 2
- Timer management of RT-Thread RTOS – Part 3
- Semaphore in RT-Thread RTOS – Part 4
- Mutex and Event in RT-Thread RTOS – Part 5
Tools and Components Required
- STM32F411 Dev Board (You can use any STM32F4 controller)
- RT-Thread Studio
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.
- Mailbox
- Message Queues
- Signals
Mailbox in RT-Thread RTOS – RT-Thread Tutorial Part 6
Mailbox
The messages can be transmitted through the mailbox. A mailbox is a special memory location that one or more tasks can use to transfer data, or more generally for synchronization.
A mailbox is a data buffer that can store a fixed number of messages of a fixed size. Threads can store messages in a mailbox. If the mailbox is full, it will return an error. So, sending messages to the mailbox is a non-blocking operation. Therefore, we can use that in the ISR. A separate function is also available for sending messages with blocking. If the mailbox is full, then it will wait until it becomes free. We cannot use this function in the ISR. Of course, threads can also retrieve messages from mailboxes. In this case, the thread is blocked if no message is available in the mailbox based on the timeout value. Any number of tasks can use the same mailbox for storing and retrieving messages.
In RT-Thread RTOS, Using the mailbox, we can transfer up to 4 bytes of data. So, it can be 32 bits of data or a pointer to the buffer. It is low overhead and high efficiency.
Management of Mailbox
In RT-Thread RTOS, the mailbox supports the below operations.
- Creating/initiating a mailbox,
- Sending messages to the mailbox,
- Receive the message from the mailbox, and
- Deleting/detaching a mailbox
Creating/initiating a mailbox
To dynamically create a mailbox object, call the following function interface:
rt_mailbox_t rt_mb_create (const char* name, rt_size_t size, rt_uint8_t flag);
Input parameters and return values of rt_mb_create()
Parameters | Description |
---|---|
name | The name of the mailbox |
size | Mailbox capacity |
flag | The mailbox flag, which can take the following values: RT_IPC_FLAG_FIFO or RT_IPC_FLAG_PRIO |
Return | —— |
RT_NULL | Creation failed |
The handle of the mailbox object | Creation successful |
You can use the below API to create the Static mailbox.
rt_err_t rt_mb_init(rt_mailbox_t mb, const char* name, void* msgpool, rt_size_t size, rt_uint8_t flag)
Input parameters and return values of rt_mb_init()
Parameters | Description |
---|---|
mb | The handle of the mailbox object |
name | Mailbox name |
msgpool | Buffer pointer |
size | Mailbox capacity |
flag | The mailbox flag, which can take the following values: RT_IPC_FLAG_FIFO or RT_IPC_FLAG_PRIO |
Return | —— |
RT_EOK | Successful |
Deleting/detaching a mailbox
You can use the below API to delete the dynamically created mailbox (mailbox which has been created using the rt_mb_create()
).
rt_err_t rt_mb_delete (rt_mailbox_t mb);
If you have used a static mailbox (mailbox which has been initialized using rt_mb_init()
), then you can use the below API to detach the mailbox.
rt_err_t rt_mb_detach(rt_mailbox_t mb);
When deleting/detaching a mailbox, if a thread is suspended on the mailbox object, the kernel first wakes up all threads suspended on the mailbox (the thread return value is –RT_ERROR
), then releases the memory used by the mailbox and finally deletes/detaches the mailbox object.
Send mail
Sending without waiting
The below API is used to send the mail to the mailbox.
rt_err_t rt_mb_send (rt_mailbox_t mb, rt_uint32_t value);
This function is not a blocking call, thus we can call this from the ISR.
The message sent can be any data 32-bit formatted, an integer value or a pointer pointing to the buffer. When the mailbox is fully filled with mails, the thread or ISR that sent the mail will receive a return value of –RT_EFULL
.
Sending with waiting
Users can also send mails to the specified mailboxes through the following function interface:
rt_err_t rt_mb_send_wait (rt_mailbox_t mb, rt_uint32_t value, rt_int32_t timeout);
The above function is blocking calls based on the timeout. If the mailbox is full, the thread sending the message will wait for the mailbox to release space as mails are received according to the set timeout parameter. So, it will be blocked until the timeout expires or the mailbox has a free space. We should not call this function from the ISR.
Note: Calling rt_mb_send_wait()
with the timeout 0 is equal to calling the rt_mb_send()
.
Receive Mails
To receive mail from the mailbox, we can use the below function.
rt_err_t rt_mb_recv (rt_mailbox_t mb, rt_uint32_t* value, rt_int32_t timeout);
Input parameters and return values of rt_mb_recv()
Parameters | Description |
---|---|
mb | The handle of the mailbox object |
value | Mail content |
timeout | Timeout |
Return | —— |
RT_EOK | Sent successfully |
-RT_ETIMEOUT | Timeout |
-RT_ERROR | Failed, return error |
Mailbox 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 mailbox. Thread 2 will be waiting for the messages in the mailbox. 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> /* Mailbox control block */ static struct rt_mailbox *mb; 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_mb_send(mb, (rt_uint32_t)&count); rt_thread_mdelay(1000); } } /* Thread 2 */ static void thread2_function(void *parameter) { uint32_t *received_mail = NULL; while (1) { /* Receive mail from the mailbox */ if (rt_mb_recv(mb, (rt_uint32_t *)&received_mail, RT_WAITING_FOREVER) == RT_EOK) { LOG_D("Thread2: Got a mail from mailbox, the message:%u\n", *received_mail); } } } int main(void) { /* create mailbox object */ mb = rt_mb_create("etx_mb", 1, RT_IPC_FLAG_FIFO); if( mb == RT_NULL ) { LOG_D("Mailbox 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; }
Output
\ | / - RT - Thread Operating System / | \ 4.1.1 build Mar 8 2023 06:51:07 2006 - 2022 Copyright by RT-Thread team ←[0m[D/main] Thread 1: count = 1 ←[0m ←[0m[D/main] Thread2: Got a mail from mailbox, the message:1 ←[0m ←[0m[D/main] Thread 1: count = 2 ←[0m ←[0m[D/main] Thread2: Got a mail from mailbox, the message:2 ←[0m ←[0m[D/main] Thread 1: count = 3 ←[0m ←[0m[D/main] Thread2: Got a mail from mailbox, the message:3 ←[0m ←[0m[D/main] Thread 1: count = 4 ←[0m ←[0m[D/main] Thread2: Got a mail from mailbox, the message:4 ←[0m ←[0m[D/main] Thread 1: count = 5 ←[0m ←[0m[D/main] Thread2: Got a mail from mailbox, the message:5 ←[0m ←[0m[D/main] Thread 1: count = 6 ←[0m ←[0m[D/main] Thread2: Got a mail from mailbox, the message:6 ←[0m
In our next tutorial, we will see the message queue in RT-Thread RTOS.
You can also read the below tutorials.
Embedded Software | Firmware | Linux Devic Deriver | RTOS
Hi, I’m SLR. I am a tech blogger and an Embedded Engineer. I am always eager to learn and explore tech-related concepts. And also, I wanted to share my knowledge with everyone in a more straightforward way with easy practical examples. I strongly believe that learning by doing is more powerful than just learning by reading. I love to do experiments. If you want to help or support me on my journey, consider sharing my articles, or Buy me a Coffee! Thank you for reading my blog! Happy learning!