本文参考RT-Thread 官方操作文档,仅用于学习。
消息队列是另一种常用的线程间通讯方式,是邮箱的扩展。可以应用在多种场合:线程间的消息交换、使用串口接收不定长数据等。
消息队列能够接收来自线程或中断服务例程中不固定长度的消息,并把消息缓存在自己的内存空间中。其他线程也能够从消息队列中读取相应的消息,而当消息队列是空的时候,可以挂起读取线程。当有新的消息到达时,挂起的线程将被唤醒以接收并处理消息。消息队列是一种异步的通信方式。
消息队列的管理
消息队列控制块是一个结构体,其中含有消息队列相关的重要参数,在消息队列的功能实现中起重要的作用。消息队列的相关接口如下图所示,对一个消息队列的操作包含:创建消息队列 - 发送消息 - 接收消息 - 删除消息队列。
本次代码实操创建两个线程,一个线程发送消息,另一个线程接收消息
#include <rtthread.h>
#include <rtdevice.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
rt_mq_t mq = RT_NULL ;
rt_thread_t send_th = RT_NULL,rece_th = RT_NULL;
void send_mq_thread_entry(void *parameter)
{
int i = 10 ,count = 0;
char buf = 'A';
rt_err_t res = RT_EOK;
while(i--){
if(i == 5){
rt_kprintf("The urgent message content is : %c\n",buf);
res = rt_mq_urgent(mq, &buf, sizeof(buf));
}else{
res = rt_mq_send(mq, &buf, sizeof(buf));
}
if ( res != RT_EOK){
LOG_E("send message queue failed...\n");
continue;
}else{
count++;
rt_kprintf("The send %d message content is : %c\n",count,buf);
}
buf++;
rt_thread_mdelay(100);
}
rt_kprintf("exit send_mq_thread_entry \n");
}
void rece_mq_thread_entry(void *parameter)
{
int count = 0;
char buf = '\0';
rt_err_t res = RT_EOK;
while(count<10){
count++;
res = rt_mq_recv(mq, &buf, sizeof(buf), 0);
if ( res != RT_EOK){
LOG_E("Receive %d message failed...\n",count);
continue;
}else{
rt_kprintf("The receive %d message content is : %c\n",count,buf);
}
rt_thread_mdelay(500);
}
rt_mq_delete(mq);
rt_kprintf("exit rece_mq_thread_entry \n");
}
int main(void)
{
// msg_size :消息队列中一条消息的最大长度,单位字节
// max_msgs: 消息队列的最大个数
mq = rt_mq_create("message queue", 64, 10,RT_IPC_FLAG_FIFO);
if( mq == RT_NULL ){
LOG_E("rt_mq_create message queue failed ...\n");
return RT_ENOMEM;
}
send_th = rt_thread_create("send_th", send_mq_thread_entry, NULL, 1024, 10, 5);
if(send_th == RT_NULL){
LOG_E("rt_thread_create[send_th] failed ...\n");
return RT_ENOMEM;
}
rece_th = rt_thread_create("rece_th", rece_mq_thread_entry, NULL, 1024, 10, 5);
if(rece_th == RT_NULL){
LOG_E("rt_thread_create[rece_th] failed ...\n");
return RT_ENOMEM;
}
rt_thread_startup(send_th);
rt_thread_startup(rece_th);
return RT_EOK;
}
实验现象:
[2022-11-12_15:40:48:125]
[2022-11-12_15:40:48:125] \ | /
[2022-11-12_15:40:48:125]- RT - Thread Operating System
[2022-11-12_15:40:48:125] / | \ 4.0.3 build Nov 1 2022
[2022-11-12_15:40:48:125] 2006 - 2020 Copyright by rt-thread team
[2022-11-12_15:40:48:125]The send 1 message content is : A
[2022-11-12_15:40:48:125]The receive 1 message content is : A
[2022-11-12_15:40:48:125]msh >The send 2 message content is : B
[2022-11-12_15:40:48:331]The send 3 message content is : C
[2022-11-12_15:40:48:441]The send 4 message content is : D
[2022-11-12_15:40:48:534]The urgent message content is : E
[2022-11-12_15:40:48:534]The send 5 message content is : E
[2022-11-12_15:40:48:628]The receive 2 message content is : E
[2022-11-12_15:40:48:644]The send 6 message content is : F
[2022-11-12_15:40:48:738]The send 7 message content is : G
[2022-11-12_15:40:48:847]The send 8 message content is : H
[2022-11-12_15:40:48:956]The send 9 message content is : I
[2022-11-12_15:40:49:050]The send 10 message content is : J
[2022-11-12_15:40:49:128]The receive 3 message content is : B
[2022-11-12_15:40:49:159]exit send_mq_thread_entry
[2022-11-12_15:40:49:644]The receive 4 message content is : C
[2022-11-12_15:40:50:144]The receive 5 message content is : D
[2022-11-12_15:40:50:644]The receive 6 message content is : F
[2022-11-12_15:40:51:144]The receive 7 message content is : G
[2022-11-12_15:40:51:644]The receive 8 message content is : H
[2022-11-12_15:40:52:156]The receive 9 message content is : I
[2022-11-12_15:40:52:658]The receive 10 message content is : J
[2022-11-12_15:40:53:158]exit rece_mq_thread_entry
发送消息线程是100ms发送一次,接收线程是500ms接收一次,所以消息发送完毕的时候,接收还未完毕,发送的第5条消息是紧急消息,当发送紧急消息时,从空闲消息链表上取下来的消息块不是挂到消息队列的队尾,而是挂到队首,这样,接收者就能够优先接收到紧急消息。
因此接收线程是先接收紧急消息‘E’,接着才接收普通消息‘B’、‘C’.....