rt-thread的IPC机制之消息队列源码分析
消息队列是另一种常用的线程间通讯方式,它能够接收来自线程的不固定长度的消息,并把消息缓存在自己的内存空间中。其他线程也能够从消息队列中读取相应的消息,而当消息队列是空的时候,可以挂起读取线程。而当有新的消息到达时,挂起的线程将被唤醒以接收并处理消息。消息队列是一种异步的通信方式。
如上图所示,通过消息队列服务,线程或中断服务子程序可以将一条或多条消息放入消息队列。同样,一个或多个线程可以从消息队列中获得消息。当有多个消息发送到消息队列时,通常先进入消息队列的消息先传给线程,也就是说,线程先得到的是最先进入消息队列的消息,即先进先出原则(FIFO)。
RT-Thread的消息队列对象由多个元素组成,当消息队列被创建时,它就被分配了消息队列控制块:队列名,内存缓冲区,消息大小以及队列长度等。同时每个消息队列对象中包含着多个消息框,每个消息框可以存放一条消息。消息队列中的第一个和最后一个消息框被分别称为队首和队尾,对应于消息队列控制块中的msg queue head和msg queue tail;有些消息框中可能是空的,它们通过msg queue free线程一个空闲消息框链表。所有消息队列中的消息框总数即是消息队列的长度,这个长度可在消息队列创建时指定。
/** * This function can get or set some extra attributions of a message queue * object. * * @param mq the message queue object * @param cmd the execution command * @param arg the execution argument * * @return the error code */rt_err_t rt_mq_control(rt_mq_t mq, rt_uint8_t cmd, void *arg){ rt_ubase_t level; struct rt_mq_message *msg; RT_ASSERT(mq != RT_NULL); if (cmd == RT_IPC_CMD_RESET)//消息重置 { /* disable interrupt */ level = rt_hw_interrupt_disable(); /* resume all waiting thread */ rt_ipc_list_resume_all(&mq->parent.suspend_thread); /* release all message in the queue */ while (mq->msg_queue_head != RT_NULL) { /* get message from queue */ msg = (struct rt_mq_message *)mq->msg_queue_head; /* move message queue head */ mq->msg_queue_head = msg->next; /* reach queue tail, set to NULL */ if (mq->msg_queue_tail == msg) mq->msg_queue_tail = RT_NULL; /* put message to free list */ msg->next = (struct rt_mq_message *)mq->msg_queue_free; mq->msg_queue_free = msg; } /* clean entry */ mq->entry = 0; /* enable interrupt */ rt_hw_interrupt_enable(level); rt_schedule(); return RT_EOK; } return -RT_ERROR;}