前面几天在逛论坛时看见有人说RTT中没有广播机制,于是心血来潮,想自己动手写一个,于是有了此文.
1 广播机制分析
广播,这个词首先让我想到Android下的广播机制,其是基于Binder来实现的,然而RTT并不是Linux内核的东东,也没有Binder这样的IPC,RTT有自己的一套IPC机制,前面的文章中有说到信号,互斥量,事件,邮箱和消息队列,我们得从这方面动动脑筋.
再回来广播这个词,现实中,电视就是一个广播的例子,我们就以电视来举例,在现实的生活中,不同的人到电视台做节目,然后家家户户就可以在电视机中收到节目了.分析一个这个模型,不同的人到电视台做节目,这里将不同的人暂且叫做广播发送者(广播可以有多个发送方),电视台提供广播发送服务,这里就叫做服务好了,然后每家都可以打开电视机接收电视节目信号,这里每台的电视机就是电视台的一个终端.
因此,这里归结一个,在RTT中,要实现广播机制,首先,广播的发送者是线程,接收者也是线程,做为发送线程和接收线程中间就需要一个服务器,专门实现将发送线程传过来的消息转发给各个已经注册的接收线程.各个接收线程看成是这个服务器的终端.在实现这个功能,首先,作为广播消息的接收终端,那么它得有一定的缓冲能力,得保存一定条数的消息,其次,作为广播的服务器,得唤醒所有等待接收的接收线程.因此,我们得分别给服务器和客户端定义一种数据结构.
2 广播服务器和客户端的控制块
在rtdef.h头文件中,在消息队列宏内添加广播控制块的定义:
//广播服务器的控制块
struct rt_broadcast_server
{
//客户端节点链表
rt_list_t client_list;
};
typedef struct rt_broadcast_server *rt_broadcast_server_t;
//广播接客户端的控制块
struct rt_broadcast_client
{ //接收消息队列
struct rt_messagequeue receive_mq;
//客户端节点
rt_list_t node;
//此广播客户端对应的服务器
//rt_broadcast_server_t server;
};
typedef struct rt_broadcast_client *rt_broadcast_client_t;
由上述可见,广播服务器控制块只包含一个链表client_list,用来保存广播客户端. 而广播客户端的控制块定义中,包含了一个消息队列receive_mq,此队列用来缓存来自广播服务器的消息,除此之外,还有一链表节点,用来作链表操作.
3 广播的接口实现
在ipc.c实现其接口:
//初始化广播服务器
rt_err_t rt_broadcast_server_init(rt_broadcast_server_t server)
{
RT_ASSERT(server !=RT_NULL);
//初始化客户端链表
rt_list_init(&(server->client_list));
return RT_EOK;
}
RTM_EXPORT(rt_broadcast_server_init);
//初始化广播客户端
rt_err_t rt_broadcast_client_init(rt_broadcast_client_t client,
const char *name,
void *msgpool,
rt_size_t msg_size,
rt_size_t pool_size,
rt_uint8_t flag)
{
rt_err_t err;
RT_ASSERT(client !=RT_NULL);
//使用传入的消息池初始化接收消息队列
err =rt_mq_init(&client->receive_mq,name,msgpool,msg_size,pool_size,flag);
if(err !=RT_EOK)
{
return err;
}
//初始化客户端节点
rt_list_init(&client->node);
return RT_EOK;
}
RTM_EXPORT(rt_broadcast_client_init);
//给广播服务器注册客户端
rt_err_t rt_broadcast_client_regist(rt_broadcast_server_t server,rt_broadcast_client_t client)
{
register rt_base_t temp;
RT_ASSERT(server !=RT_NULL);
RT_ASSERT(client !=RT_NULL);
//开关断
temp = rt_hw_interrupt_disable();
//将客户端节点注册到到服务器
rt_list_insert_after(&server->client_list,&client->node);
//开中断
rt_hw_interrupt_enable(temp);
return RT_EOK;
}
RTM_EXPORT(rt_broadcast_client_regist);
//卸载一个客户端
rt_err_t rt_broadcast_client_unregist(rt_broadcast_client_t client)
{
register rt_base_t temp;
RT_ASSERT(client !=RT_NULL);
//关中断
temp = rt_hw_interrupt_disable();
//将客户端节点从服务器上移除
rt_list_remove(