消息队列基本概念:

队列又称消息队列,是一种常用于线程间通信的数据结构,队列可以在线程和线程间,中断和线程间传送消息,实现线程可以从其他线程或者中断中接收不定长消息。消息队列是一种异步的通信方式。

消息队列能够从队列中读取消息,当队列中消息是空的时候,挂起线程,用户还可以指定线程挂起的时间,有新消息,线程被唤醒挂起然后处理新消息。
通过消息队列服务,线程或中断服务例程可以将一条或多条消息放入消息队列中。同样,一个或多个线程可以从消息队列中获得消息。
当有多个消息发送到消息队列时,通常是将先进入消息队列的消息先传给线程,也就是说,线程先得到的是最先进入消息队列的消息,即先进先出原则(FIFO)。

消息队列基本特征

RT-Thread 中使用队列数据结构实现线程异步通信工作,具有如下特性:
·消息支持先进先出方式排队与优先级排队方式,支持异步读写工作方式。·读队列支持超时机制。
·支持发送紧急消息,这里的紧急消息是往队列头发送消息。
·可以允许不同长度(不超过队列节点最大值)的任意类型消息。·一个线程能够从任意一个消息队列接收和发送消息。·多个线程能够从同一个消息队列接收和发送消息。
·当队列使用结束后,需要通过删除队列操作释放内存函数回收。

创建消息队列

1创建消息队列时先创建一个消息队列对象控制块;
2然后给消息队列分配一块内存空间,组织成空闲消息链表,这块内存的
大小等于[消息大小+消息头(用于链表连接)]与消息队列容量的乘积;3接着再初始化消息队列,此时消息队列为空。

// 创建一个消息队列控制块,
static rt_mq_t test_mq = RT_NULL;

队列工作原理

线程或者中断服务程序都可以给消息队列发送消息。
1当发送消息时,消息队列对象先从空闲消息链表上取下一个空闲消息块,
把线程或者中断服务程序发送的消息内容复制到消息块上;然后把该消息块挂到消息队列的尾部。
2当且仅当空闲消息链表上有可用的空闲消息块时,发送者才能成功发送消息;
3当空闲消息链表上无可用消息块,说明消息队列已满,此时,发送消息的线程或者中断程序会收到一个错误码(-RT_EFULL)。

队列工作示意图:

读取消息

1:线程A扭头就走,既然队列没有消息,那我也不等了,干其它事情去,这样子线程 A 不会进入阻塞态;
2:线程A还是在这里等等吧,可能过一会队列就有消息,此时线程A会进入阻塞状态,在等待着消息的道来,而线程A的等待时间就由我们自己定义,比如设置1000个 tick的等待,在这1000个tick到来之前线程A都是处于阻塞态,当阻塞的这段时间线程A等到了队列的消息,那么线程A就会从阻塞态变成就绪态,如果此时线程 A比当前运行的线程优先级还高,那么,线程A就会得到消息并且运行;假如1000个tick都过去了,队列还没消息,那线程A就不等了,从阻塞态中唤醒,返回一个没等到消息的错误代码,然后继续执行线程A的其他代码;
3:线程A死等,不等到消息就不走了,这样子线程A就会进入阻塞态,直到完成读取队列的消息。

发送消息

在发送消息操作的时候,为了保护数据,当且仅当空闲消息链表上有可用的空闲消息块时,发送者才能成功发送消息;
当空闲消息链表上无可用消息块,说明消息队列已满,此时,发送消息的的线程或者中断程序会收到一个错误码(-RT_EFULL),发送消息并不带有阻塞机制的,因为发送消息的环境可能是在中断中,不允许有阻塞的情况。

需要使用的常用函数:

紧急消息

发送紧急消息的过程与发送消息几乎一样,唯一的不同是,当发送紧急消息时,从空闲消息链表上取下来的消息块不是挂到消息队列的队尾,而是挂到队首,这样,接收者就能够优先接收到紧急消息,从而及时进行消息处理

队列应用:

实验内容:
在RT-Thread中创建了两个线程,一个是发送消息线程,一个是获取消息线程,两个线程独立运行,发送消息线程是通过检测按键的按下情况来发送消息,假如发送消息不成功,就把返回的错误情代码在串口打印出来,另一个线程是获取消息线程,在消息队列没有消息之前一直等待消息,一旦获取到消息就把消息打印在串口调试助手里。

注意:在使用消息队列时候请确保在rtconfig.h 中打开RT USING MESSAGEQUEUE 这个宏定义

这里我们只提供书写相关思路,具体代码可以在代码仓库找到!!!

static rt_thread_t receive_thread = RT_NULL;  //定义接收消息线程句柄
static rt_thread_t send_thread = RT_NULL;  //定义发送消息线程句柄
static rt_mq_t test_mq= RT_NULL; // 定义消息队列句柄

//   打印出实验的目的:
  rt_kprintf("这是一个RTT消息队列实验! \n");
		 rt_kprintf("按下不同按键显示不同消息! \n");
		 
	
// 创建消息队列
   test_mq=rt_mq_create("test_mq",      //  消息队列的名字
                         40,            //  消息最大长度
                         20,            //消息队列最大容量
                         RT_IPC_FLAG_FIFO  // 队列模式
);
		if(test_mq!=RT_NULL)
		rt_kprintf("消息队列创建成功\n");
		
// 创建接收发消息线程
		
		receive_thread=rt_thread_create("receive",receive_thread_entry,RT_NULL,512,3,20);
		if(receive_thread!=RT_NULL)
			rt_thread_startup(receive_thread);	
		else
			return-1;
		
		send_thread=rt_thread_create("send",send_thread_entry,RT_NULL,512,2,20);
		if(send_thread!=RT_NULL)
			rt_thread_startup(send_thread);	
		else
			return-1;
// 声明接收发函数:后面自己填写函数具体要求:
static void receive_thread_entry(void* parameter);
static void send_thread_entry(void* parameter);

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐