消息队列的应用场景:
消息的主要作用——用于任务/线程、中断服务例程之间的通信,主要是信息交换,他的一大特点:可以接收长度定制的消息。
队列的主要作用——实现任务/线程、中断服务例程之间的异步通信,所谓的异步通信的就是接收到消息可以先做缓存,不用立即处理,立即处理的话就叫同步通信,因为要缓存,所以才需要队列,你可以把队列看成一种数据结构,实际上他也的确是数据结构,一般应用链表来实现。
消息队列控制块——消息队列状态信息存储
消息队列控制块的实现(站在应用的角度是可以忽略这一部分,你只要知道他是一种数据类型就OK了):
struct rt_messagequeue
{
struct rt_ipc_object parent; /*它爸爸*/
void* msg_pool; /* 指向存放消息的缓冲区的指针 */
rt_uint16_t msg_size; /* 消息的长度 */
rt_uint16_t max_msgs; /* 最大能够容纳的消息数 */
rt_uint16_t entry; /* 队列中已有的消息数 */
void* msg_queue_head; /* 指针指向——消息链表头 */
void* msg_queue_tail; /* 指针指向——消息链表尾 */
void* msg_queue_free; /* 指针指向——空闲消息链表 */
rt_list_t suspend_sender_thread; /* 发送线程的挂起等待队列 */
};
typedef struct rt_messagequeue* rt_mq_t;
其实关于消息队列控制块,你只需要知道它和他的指针如何定义就够了,重要的是:
struct rt_messagequeque msg_1; /*创建一个消息队列控制块对象*/
rt_mq_t *msg_1;/*创建一个消息队列控制块的引用*/
消息队列的应用API接口(只关注静态类型,不要问为什么不聊动态,问就是不会。。。):
1.初始化消息队列API(悄悄告诉你,其实初始化就是用一堆参数来初始化mq参数):
/*rt_err_t:用于判断初始化是否成功的返回值,正常情况下返回:RT_EOK*/
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); /*消息队列采用的等待方式,基本默认:RT_IPC_FLAG_PRIO*/
2.有初始化消息队列API,就得有脱离消息队列API(用的时候初始化,不用的时候要脱离):
/*rt_err_t:用于判断脱离消息队列是否成功的返回值,正常情况下返回:RT_EOK*/
rt_err_t rt_mq_detach(rt_mq_t mq);/*消息队列对象的句柄*/
3.1发送一条消息到消息队列,有多种API,主要区别发送是否需要等待超时,发送消息是否为紧急消息,什么情况下发送不能用等待超时呢?(举个栗子,中断服务例程是不能才用等待超时发送的,于是就要才用第一种立即发送):
/*rt_err_t:发送消息到消息队列是否成功,
消息队列有空闲时,发送成功:RT_EOK
消息队列为满时,发送为满:-RT_EFULL
发送消息大于消息队列最大消息长度时,发送失败:-RT_ERROR*/
rt_err_t rt_mq_send (rt_mq_t mq, /*消息队列对象的句柄*/
void* buffer, /*发送消息内容的指针*/
rt_size_t size);/*发送消息的大小*/
3.2采用等待超时方式发送消息到消息队列API:
/*rt_err_t:发送消息到消息队列是否成功,
消息队列有空闲时,发送成功:RT_EOK
消息队列为满时,发送为满:-RT_EFULL
发送消息大于消息队列最大消息长度时,发送失败:-RT_ERROR*/
rt_err_t rt_mq_send_wait(rt_mq_t mq, /*消息队列对象的句柄*/
const void *buffer, /*发送消息内容的指针*/
rt_size_t size, /*发送消息的大小*/
rt_int32_t timeout); /*超时时间*/
3.3才用紧急发送消息与第一种无等待发送很相似,不同的是消息被插入消息队列的位置不一样(紧急发送消息插入链表头部,非紧急发送消息插入链表尾部):
/*rt_err_t:发送消息到消息队列是否成功,
消息队列有空闲时,发送成功:RT_EOK
消息队列为满时,发送为满:-RT_EFULL
发送消息大于消息队列最大消息长度时,发送失败:-RT_ERROR*/
rt_err_t rt_mq_urgent (rt_mq_t mq, /*消息队列对象的句柄*/
void* buffer, /*发送消息内容的指针*/
rt_size_t size);/*发送消息的大小*/
4.从消息队列中接收消息API:
/*rt_err_t:从消息队列接收消息是否成功:RT_EOK
超时:-RT_ETIMEOUT
接收失败:-RT_ERROR*/
rt_err_t rt_mq_recv (rt_mq_t mq, /*消息队列对象的句柄*/
void* buffer, /*接收消息的内容指针*/
rt_size_t size,/*接收消息的大小*/
rt_int32_t timeout); /*超时时间*/
创建一个基于消息队列的应用:
1.关于消息队列初始化应用:
/* 消息队列控制块 */
static struct rt_messagequeue mq;
/* 消息队列中用到的放置消息的内存池 */
static rt_uint8_t msg_pool[2048];
rt_err_t result;
/* 初始化消息队列 */
result = rt_mq_init(&mq,
"mqt",
&msg_pool[0], /* 内存池指向 msg_pool */
1, /* 每个消息的大小是 1 字节 */
sizeof(msg_pool), /* 内存池的大小是 msg_pool 的大小 */
RT_IPC_FLAG_PRIO); /* 如果有多个线程等待,优先级大小的方法分配消息 */
if (result != RT_EOK)
{
rt_kprintf("init message queue failed.\n");
return -1;
}
2.发送消息到消息队列应用:
int result;
char buf = 'A';
/* 发送消息到消息队列中 */
result = rt_mq_send(&mq, &buf, 1);
if (result != RT_EOK)
{
rt_kprintf("rt_mq_send ERR\n");
}
3.从消息队列接收消息应用:
char buf = 0;
/* 从消息队列中接收消息 */
if (rt_mq_recv(&mq, &buf, sizeof(buf), RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("thread1: recv msg from msg queue, the content:%c\n", buf);
}