VxWorks学习笔记——任务间通信之消息队列

本文主要对任务间通信机制中的消息队列进行总结介绍。

信号量的同步和互斥机制可以方便、高效地协调人物,但是无法提供完善的响应式交互信息方式。因此引入消息队列。

工作方式

  • 多个任务可以同时操作同一个消息队列或者向其发送消息,或者接收消息。对于ISR,可以设置为不等待(NO_WAIT)的方式向其发送消息。在创建消息队列时,需要指定消息队列长度(最大消息数)以及每条变长消息的最大长度,以及任务的排队方式等。
  • 若多个任务之间需要进行全双工交互,那么最好为每个任务创建一个消息队列(可以理解为每个人物都拥有一个自己的信箱)。

状态

刚创建好的消息队列是空的,此时消息队列处于空状态。向消息队列发送/接收消息,其结果是增加/减少消息队列中消息的数目;当数目达到消息队列长度时,消息队列为满状态。消息队列处于空状态与满状态之间时,统称为非空状态。

常用函数

消息队列的创建

  • 消息队列通过msgQCreate函数来创建,系统将统一分配一个消息队列ID,所有操作都将围绕这个ID进行。

  • 1
    2
    3
    4
    5
    6
    MSG_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
    8
    STATUS 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
    7
    int msgQReceive
    (
    	MSG_Q_ID msgQId,		/* 消息队列ID */
        char *buffer,			/* 指向接收消息的缓冲的指针 */
        UINT maxNBytes,	 		/* 接收缓冲的字节数 */
        int timeout				/* 超时参数,单位为tick */
    )
    
  • 消息队列非空时,消息队列中的第一条消息会立即被任务取出。

  • 各项参数含义同发送函数

  • ISR不能调用msgQReceive操作
1
向消息队列发送或者接收消息时,消息的内容均采用拷贝的方式。因此需要尽量避免使消息队列中每条消息的长度过大,以提高消息队列的操作速度,并节省空间。传送长消息时,可将被传送内容的地址指针作为消息传送。