本文分享自中移OneOS公众号《任务间通信》。
上篇讲解了任务间同步,在本篇中主要讲解任务间通信机制,并对邮箱及消息队列进行详细介绍。通过对其概念、详细设计、接口设计等的讲解帮助开发者更好的理解其在操作系统中的应用。
任务间通信是指在不同任务之间传播或交换信息,操作系统实现的通信机制包含邮箱和消息队列。
邮箱
邮箱机制规定,一封邮件是固定的4字节大小,比较适合交换占用较小空间的信息,或者交换指针信息。
发送邮件实际是将发送缓存的4字节内容拷贝到邮箱,接收邮件是将邮箱中的4字节内容拷贝到接收缓存,如下图。
<邮箱通信示意图>
邮箱包含阻塞和非阻塞两种方式,其中,
阻塞方式:
1)如果邮箱为空时选择接收邮件,任务会被挂起,直到有新的邮件进入邮箱,挂起任务被唤醒接收邮件,或者设置的超时时间到达返回错误;
2)如果邮箱已满时选择发送邮件,任务也会被挂起,直到有其他任务接收邮件,邮箱有空间后挂起任务重新进入就绪态发送,或者设置的超时时间到达返回错误。
非阻塞方式:
1)如果邮箱为空时选择接收邮件,或者邮箱已满时选择发送邮件,都是直接返回错误。该方式适用于中断服务、定时器等不能阻塞的场景。
邮箱控制块结构的详细定义如下:
struct os_mailbox
{
os_ipc_object_t parent;
os_uint32_t *msg_pool; /* 邮箱缓冲区的开始地址*/
os_uint16_t size; /* 邮箱缓冲区的大小 */
os_uint16_t entry; /* 邮箱中邮件的数目 */
os_uint16_t in_offset, /* 邮箱缓冲的进指针*/
os_uint16_t out_offset; /* 邮箱缓冲的出指针*/
os_list_node_t suspend_sender_task; /* 发送任务的挂起等待队列*/
};
邮箱接口设计如下:
(1)创建邮箱
(2)销毁邮箱
(3)发送邮件
(4)等待方式发送邮件
(5)接收邮件
消息队列
因为邮箱一次只能发送固定大小的4字节,在很多场景下使用不便,系统实现了另一种更通用的任务间通讯方式--消息队列。
消息队列初始化时,需要传入消息大小和数量作为参数,由系统初始化所需要使用的内存空间。初始化后的结构如下图。
<消息队列初始化示意图>
发送消息时,选择queue_free指向的地址,如果为空表示队列已满,拷贝发送缓存到消息体,queue_free指针往后移指向next指针所在的地址,当前消息连接到queue_tail指向的链表。消息拷贝完成后,系统还会检测是否有任务在该队列上等待,如有则进行唤醒,根据优先级选择是否马上调度到唤醒任务执行。
接收消息时,检查是否有未读消息,如果没有可以选择阻塞等待或者返回错误,有消息时从queue_head取出第一条可用消息拷贝至接收缓存,queue_head移到next指向的下一条消息。
对于某些场景,有紧急消息需要马上得到处理,消息队列增加了发送紧急消息的功能,数据拷贝到消息体后,queue_head指针会指向紧急消息地址,以保证下一次消息接收可以马上获取到。发送紧急消息后的内存指针分布如下图。
<紧急消息示意图>
消息队列控制块结构的详细定义如下:
struct os_mq
{
os_ipc_object_t parent;
os_mq_msg_list_t msg_pool; /* 指向存放消息的缓冲区的指针*/
os_uint16_t msg_size; /* 每个消息的长度*/
os_uint16_t max_msgs; /* 最大能够容纳的消息数*/
os_uint16_t entry; /* 队列中已有的消息数*/
void *msg_queue_head; /* 消息链表头*/
void *msg_queue_tail; /* 消息链表尾*/
void *msg_queue_free; /* 空闲消息链表*/
};
消息队列接口设计如下:
(1)创建消息队列
(2)销毁消息队列
(3)发送消息
(4)等待方式发送消息
(5)发送紧急信息
(6)接收消息
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)