本文主要对任务间通信机制中的消息队列进行总结介绍。
信号量的同步和互斥机制可以方便、高效地协调人物,但是无法提供完善的响应式交互信息方式。因此引入消息队列。
工作方式
- 多个任务可以同时操作同一个消息队列或者向其发送消息,或者接收消息。对于ISR,可以设置为不等待(NO_WAIT)的方式向其发送消息。在创建消息队列时,需要指定消息队列长度(最大消息数)以及每条变长消息的最大长度,以及任务的排队方式等。
- 若多个任务之间需要进行全双工交互,那么最好为每个任务创建一个消息队列(可以理解为每个人物都拥有一个自己的信箱)。
状态
刚创建好的消息队列是空的,此时消息队列处于空状态。向消息队列发送/接收消息,其结果是增加/减少消息队列中消息的数目;当数目达到消息队列长度时,消息队列为满状态。消息队列处于空状态与满状态之间时,统称为非空状态。
常用函数
消息队列的创建
-
消息队列通过msgQCreate函数来创建,系统将统一分配一个消息队列ID,所有操作都将围绕这个ID进行。
-
1
2
3
4
5
6MSG_Q_ID msgQCreate ( int maxMsgs, /* 消息队列长度(消息队列中最大消息个数)*/ int maxMsgLength, /* 消息队列中消息的最大长度 */ int options /* 选项 */ )
-
选项与信号量类似,有三种取值
- MSG_Q_PRIORITY:阻塞在消息队列上的所有任务的排队规则为基于任务的优先级
- MSG_Q_FIFO:阻塞在消息队列上的所有任务的排队规则是先进先出。二者必须二选一
-
MSG_Q_EVENTSEND_ERR_NOTIFY:该选项默认无效,如果需要可以用排队规则用按位或(“ ”)一起使用。设置了此选项时,如果发送失败会返回ERROR
消息队列的删除
- 消息队列的删除使用函数msgQDelete
- 该函数仅有一个参数为消息队列ID
- 该函数执行完毕后,阻塞在该消息队列上的任务,包括足额色在发送队列、接收队列以及等待时间队列上的任务,都将被唤醒,而消息队列的ID此后不再有效。
消息队列的发送
-
发送调用函数msgQSend,可以将一条消息发送到指定的消息队列。执行后成功返回OK,反之返回ERROR,并利用全局变量errno给出出错原因。
-
1
2
3
4
5
6
7
8STATUS msgQSend ( MSG_Q_ID msgQId, /* 消息队列ID */ char *buffer, /* 指向要发送的消息的指针 */ UINT nBytes, /* 消息长度 */ int timeout, /* 超时参数,单位为tick */ int priority /* MSG_PRI_NORMAL 或 MSG_PRI_URGENT*/ )
-
当消息队列中有多条消息时,这些消息将在消息队列上排队。一般来说按照FIFO通过消息队列,此时调用参数为MSG_PRI_NORMAL
-
如果需要将新来的消息插在消息队列头部,需要指定优先级参数为MSG_PRI_URGENT,表明这是一条紧急的消息
-
当消息队列已满时,任务会阻塞等待消息队列中有空间空出,超时参数给出任务等待超时的时间,以tick为单位。超市之前,一旦任务有机会将消息送入队列,将退出阻塞状态。若直到超时都未送出消息,则任务同样会退出则色状态,但msgQSend会返回ERROR
-
timeout参数有两个特殊的取值
- NO_WAIT表示调用msgQSend的任务不会被阻塞
- WAIT_FOREVER表示调用的任务会一直阻塞,直至可以将消息发送至消息队列
消息队列的接收
-
调用函数为msgQRecive
-
1
2
3
4
5
6
7int msgQReceive ( MSG_Q_ID msgQId, /* 消息队列ID */ char *buffer, /* 指向接收消息的缓冲的指针 */ UINT maxNBytes, /* 接收缓冲的字节数 */ int timeout /* 超时参数,单位为tick */ )
-
消息队列非空时,消息队列中的第一条消息会立即被任务取出。
-
各项参数含义同发送函数
- ISR不能调用msgQReceive操作
1 |
|