7.消息传递

来源:互联网 发布:会员卡充值软件 编辑:程序博客网 时间:2024/05/15 10:42

任务间消息传递主要有两种方式:全局变量,发布消息;前者在资源管理中讨论过

  • 消息及消息队列:
    • 消息:
      • 组成部分:1,指向数据指针,2,数据长度,3,消息发布时刻时间戳;
      • 接收双方应就消息内容达成约定,消息中指针使用的很灵活,可指向数据区,函数等;
      • 消息内容应保持可见性:
        • 消息传递的是指针,而非直接的数据;
        • 需确保接收任务可以访问指针所指向区域,而不会由于作用域等原因无法访问或访问失效;
      • 消息发布后会被放入OS_MSG类型结构体内,结构体内包含四个域:
        • NextPtr:指向下一个OS_MSG(一则则消息构成队列)
        • MsgSize,MsgTS,MsgPtr:分别表示上述消息的三部分;
        • 需弄清OS_MSG是消息载体,而非消息本身;
      • 系统维护一个空闲OS_MSG缓冲池,总数由OS_CFG_MSG_POOL_SIZE(os_cfg_app.h)决定;
      • 初始化时,所有OS_MSG组成单向链表,由结构体OS_MSG_POOL维护,NextPtr指向第一个空闲OS_MSG

 

 

  • 消息队列:
    • 消息队列作为内核对象OS_Q(os.h),和其他内核对象类似:
      • OS_OBJ_TYPE表类型,还可包含一个其的等待表;
      • 其中还有一个OS_MSG_Q结构体维护消息队列;
    • 消息组成的消息队列由OS_MSG_Q结构体维护,其包括5个域:
      • InPtr:指向下个OS_MSG要插入的位置,即InPtr所指向的OS_MSG之后;
      • OutPtr:指向下一个要被取出OS_MSG位置;
      • NbrEntriesSize,NbrEntries:分别表示消息队列最多能容纳OS_MSG的数目,当前已容纳数目;若达到最大值,程序向此队列发的消息会被丢弃;
      • NbrEntries:表明此队列消息数曾到达过的最大值;

 

  • 任务内建的消息队列:
    • 多个任务等待同一消息队列不常见,uCOSIII允许每个任务有内建消息队列;

  • OS_CFG_TASK_Q_EN(os_cfg.h)=1时即可启用此服务,相关函数在os_task.c内;
  • OS_TCB内会申明一个OS_MSG_Q

 

  • 消息队列函数:
    • 系统内部维护消息链的函数(os_msg.c)
      • OS_MsgQPut():把一个OS_MSG放入消息队列;
      • OS_MstQGet():从消息队列中取出一个OS_MSG
      • OS_MsgQFreeAll():把消息队列中所有OS_MSG释放回空闲OS_MSG缓冲池;
    • 消息队列函数:

  • 任务创建OSQCreate(OS_Q *p_q, CPU_CHAR *p_name, OS_MSG_QTY max_qty, OS_ERR *p_err)
    • 创建前先声明一个队列,max_qty是消息队列的最大长度;
  • 发消息:OSQPost(OS_Q *p_q, void *p_void, OS_MSG_SIZE msg_size,OS_OPT opt, OS_ERR *p_err)
    • 发布消息时消息队列满则消息会丢失,error会返回相关错误类型;
    • opt选项可能有OS_OPT_POST_FIFOOS_OPT_POST_LIFOOS_OPT_POST_ALLOS_OPT_POST_NO_SCHED,可按一定规律组合使用;
  • 等待消息:void *OSQPend(OS_Q *p_q, OS_TICK timeout, OS_OPT opt,OS_MSG_SIZE *p_msg_size, CPU_TS *p_ts, OS_ERR *p_err)
    • opt还是有OS_OPT_PEND_BLOCKINGOS_OPT_PEND_NON_BLOCKING两种可选;
  • 任务内建消息队列函数:

  • 这些函数具体和上面类似,只是应注意无需指明哪个消息队列,而是指明相关OS_TCB

 

  • 消息队列使用及信息传递中的一些问题:
    • 基本点:
      • 消息队列访问可采用FIFOLIFO方式;
      • 可以一个或多个任务向队列中发消息,一个或多个任务从队列中等待接收消息;
      • 一则消息可使等待的最高优先级任务进入就绪态,发送方发送消息时亦可指定广播;
    • 双向同步:
      • 只能用于TaskTask之间,因为ISR无法等待消息操作;
      • 此时每个消息队列内最多容纳1则消息,初始化时均为空;

  • 左边任务执行到同步点时,向上方消息队列发送1则消息;
  • 之后等待下方消息队列内的消息;
  • 右边的则相对应,执行到同步点时,向下方消息队列发一则消息,然后等待上方消息;
  • 此两个队列也可以是任务内建消息队列;

 

  • 流量控制(生产者-消费者问题)
    • 一个任务生产数据,一个任务消费数据,生产者生产速度可能高于消费者,使队列溢出;
    • 在传递消息过程加入计数型信号量,即流量控制;

  • 信号量值初始值为允许生产者发布的消息数目;
  • 生产者发布消息前必须获得信号量(信号量不为0),消费者处理完一则消息,释放一个信号量;
  • 可用任务内建消息队列和内建信号量来实现,消费者建立任务后调用OS_TaskSemSet()设置内建信号量值为生产者消息队列最大长度;

 

  • 保持数据可见:
    • 发送方一旦发送一个指向相关数据结构的指针后,这些数据需保持不变到接收方收到;
    • 为达到此目的使用堆区存放传递数据:
      • 要传递信息前申请一块堆区存储欲传输数据;
      • 传送指针到消息队列,接收方接收;
      • 收到后接收方处理数据,释放堆区(小心内存泄漏)
      • 这样可以解决作用域的限定问题;

 

  • 客户端-服务器:
    • 一个任务(服务器)专门监视其他Task/ISR(客户端)的系统运行错误情况;

  • 消息内容除了错误的内容外还可以包括处理错误的函数的地址;
0 0