一种基于共享内存的实时数据分发方法及装置
文献发布时间:2023-06-19 10:08:35
技术领域
本申请属于计算机通信技术领域,具体涉及一种基于共享内存的实时数据分发方法及装置。
背景技术
由于CPU单核性能提升有限,因此目前高性能CPU设计向着多核多线程发展,应用程序为了更高效地利用CPU资源,同时为了避免因单个进程崩溃导致应用程序提供的业务停止,通常选用基于多进程开发的应用程序架构作为复杂应用程序的首选架构。与单进程多线程应用程序不同的是:多进程应用程序的进程间数据空间隔离不能像多线程架构一样直接共享数据。因此多进程架构应用程序需要高效的消息传递以及数据分发机制。多进程架构应用程序间的通信依赖操作系统底层通信机制,通常操作系统底层通信机制为兼顾通用性功能较为简单,要实现复杂数据分发机制,尤其涉及到支持一对一、一对多、多对一和多对多数据分发时,需要设计一套复杂数据交互机制。
目前常见的多进程架构的应用程序间数据分发方法有基于TCP/IP网络通信与自定义协议相结合方式实现,有基于消息总线(如DDS中间件)方式实现,也有基于操作系统提供的消息队列实现消息发送和读取,完成一对一、多对一的数据分发。
但是现有技术在性能、实时性和通用性上存在不少缺点。基于TCP/IP网络通信与自定义协议的实现性能受限于操作系统网络协议栈的实现,单机内部使用网络通信性能较低;接收模块和发送模块的IP和端口信息无法实时共享,需要设计转发模块,数据在收发模块和转发模块之间多次拷贝,通信效率低、时延大,不能满足实时性要求较高的使用场合(如机器人运动控制、自动驾驶控制);自定义通信协议缺乏规范和标准,通常与应用框架耦合性很高,通用性较差。
基于消息总线(如DDS中间件)实现的数据分发一般多用于多机之间数据收发,也是基于TCP/IP协议实现,同样存在实时性问题和性能问题,且该类中间件实现复杂,依赖库众多,是重量级消息总线,无法简单应用到实时性要求高的嵌入式系统中。
基于操作系统提供的消息队列实现数据分发的方式,消息队列对单个消息的数据长度有限制,修改长度限制需要对操作系统内核参数进行配置,难以形成通用框架;更重要的是消息队列仅支持一对一,多对一的数据分发,不能实现一对多、多对多的数据收发;操作系统实现的消息队列,在用户空间和内核空间存在四次内存拷贝,通信效率低。消息队列发送和接收四次数据拷贝过程如图1所示,消息发送时通过系统调用将用户缓存拷贝内核缓存,从内核缓存拷贝到消息队列,消息接收时从消息队列拷贝消息到内核缓存并从内核缓存通过系统调用拷贝至接收用户缓存。
发明内容
本申请的目的在于一种基于共享内存的实时数据分发方法及装置,减少数据分发过程中的拷贝次数,通用性强。
为实现上述目的,本申请所采取的技术方案为:
一种基于共享内存的实时数据分发方法,用于多进程间的数据分发,多进程中用于发布数据的为发布进程,用于接收数据的为接收进程,所述基于共享内存的实时数据分发方法,包括:
所述发布进程和接收进程加载数据分发组件,所述数据分发组件申请有多个共享内存通道,每个共享内存通道用于一个数据主题的数据分发;
所述接收进程订阅感兴趣的数据主题,并向所述数据分发组件申请共享内存通道,固定所申请的共享内存通道的数据主题为所订阅的数据主题;
所述发布进程发布数据到数据所属数据主题对应的所有共享内存通道;
所述接收进程定时查询所申请的共享内存通道中是否有数据,若有则接收所述共享内存通道中的数据;否则继续定时查询。
以下还提供了若干可选方式,但并不作为对上述总体方案的额外限定,仅仅是进一步的增补或优选,在没有技术或逻辑矛盾的前提下,各可选方式可单独针对上述总体方案进行组合,还可以是多个可选方式之间进行组合。
作为优选,所述数据分发组件包括通道管理单元和模块ID管理单元,并且各进程携带有独立的进程ID,所述发布进程和接收进程加载数据分发组件时,所述数据分发组件自动完成通道管理单元初始化和模块ID管理单元初始化,其中:
所述模块ID管理单元初始化包括:
首次初始化时,申请模块管理共享内存,设置所述模块管理共享内存的布局,申请多个全局唯一的模块ID;非首次初始化时,挂接相应的模块管理共享内存,使用已申请的多个全局唯一的模块ID;
所述模块管理共享内存的布局为内存地址从低到高依次为上次分配的模块ID、进程ID数组和模块状态数组,所述进程ID数组和模块状态数组的大小相同且与模块ID的个数相等,所述进程ID数组以模块ID-进程ID的格式进行存储,所述模块状态数组以模块ID-模块状态的格式进行存储;所述模块ID管理单元初始化后所述上次分配的模块ID初始化为0,进程ID数组初始化为空,模块状态数组初始化为空闲;
所述通道管理单元初始化包括:
首次初始化时,申请通道管理共享内存,设置所述通道管理共享内存的布局,申请多个全局唯一的通道ID;非首次初始化时,挂接相应的通道管理共享内存,使用已申请的多个全局唯一的通道ID;
所述通道管理共享内存的布局为内存地址从低到高依次为上次分配的通道ID和通道信息数组,其中通道信息数组的大小与共享内存通道的数量相等,通道信息数组中的每个元素用于记录通道ID以及该共享内存通道的属性,所述共享内存通道的属性包括通道对应的共享内存Key、共享内存大小、信号量Key、数据主题ID、模块ID、订阅者线程ID、订阅者进程ID、通道使用状态和通道清理状态;所述通道管理单元初始化后所述上次分配的通道ID初始化为0,通道信息数组初始化为默认值。
作为优选,所述发布进程和接收进程加载数据分发组件后,模块ID管理单元为每一进程分配各自的模块ID,并更新上次分配的模块ID、进程ID数组和模块状态数组。
作为优选,所述共享内存通道中包含一个共享内存队列,所述共享内存队列为FIFO队列,所述共享内存队列的列头Head指针记录第一包数据包头的相对指针,所述共享内存队列的列尾Tail指针记录最后一包数据包头的相对指针,所述相对指针为相对于共享内存通道的起始地址的偏移量。
作为优选,所述发布进程发布数据到数据所属数据主题对应的所有共享内存通道,包括:
挂接所述通道管理共享内存;
基于所述通道管理共享内存获取固定为指定数据主题的所有共享内存通道的通道ID;
根据所述通道ID判断对应的通道信息数组中的通道清理状态是否为待清理,清理所有通道清理状态为待清理的共享内存通道;
动态挂接剩余的共享内存通道中的共享内存队列;
发送数据至每一共享内存队列中。
作为优选,所述接收进程定时查询所申请的共享内存通道中是否有数据,若有则接收所述共享内存通道中的数据;否则继续定时查询,包括:
挂接所述通道管理共享内存;
基于所述通道管理共享内存获取所述接收进程所订阅的指定数据主题的共享内存通道的属性;
根据所述共享内存通道的属性挂接共享内存通道中共享内存队列;
判断共享内存队列中是否有数据,若有数据则获取数据包大小、数据包发布时间;
根据获取的数据包大小、数据包发布时间从共享内存队列中读取数据。
作为优选,所述基于共享内存的实时数据分发方法,还包括接收进程退订数据主题,所述接收进程退订数据主题,包括:
挂接所述通道管理共享内存;
遍历所述通道管理共享内存,基于进程ID和将要退订的数据主题查找相应的通道ID;
根据查找到的通道ID从相应通道管理共享内存获取共享内存通道的属性,根据共享内存通道的属性挂接共享内存队列;
设置共享内存通道的属性中的通道使用状态为空闲,释放共享内存队列的资源,标识通道清理状态为待清理。
作为优选,所述基于共享内存的实时数据分发方法,还包括当所有进程均退订数据主题时,由最后退订的进程销毁数据分发组件,其中销毁数据分发组件包括所述模块ID管理单元销毁和通道管理单元销毁;
所述模块ID管理单元销毁,包括:清理所述模块管理共享内存,回收模块ID;
所述通道管理单元销毁,包括:清理通道管理共享内存,回收通道ID。
本申请还提供一种基于共享内存的实时数据分发装置,包括存储器和处理器,所述存储器存储有计算机程序,所述处理器执行所述计算机程序时实现上述任一项技术方案所述的基于共享内存的实时数据分发方法。
本申请提供的基于共享内存的实时数据分发方法及装置,通过在共享内存上开辟不同共享内存通道,建立共享内存通道与数据主题的对应关系,发布进程发送数据到特定数据主题上,接收进程从订阅的数据主题上接收数据,通过向主题发布和订阅数据解耦了多个进程之间的关联,从而实现进程间的一对一、一对多和多对多的数据分发;并且不同程序数据收发只有2次内存拷贝且不需要进入操作系统内核态,减少了数据拷贝过程,缩短了数据传输路径,大幅提升数据分发效率和实时性。另外,本发明提供的数据分发组件独立于应用程序业务逻辑,适用于所有单机多个应用软件数据分发的场景,通用性很强。
附图说明
图1为现有技术中数据分发流程图;
图2为本申请基于共享内存的实时数据分发方法的流程图;
图3为本申请接收进程注册订阅过程流程图;
图4为本申请发布进程发布数据的流程图;
图5为本申请接收进程退订数据主题的流程图;
图6为本申请基于共享内存的实时数据分发方法的一种实施例示意图;
图7为本申请基于共享内存的实时数据分发装置的结构示意图。
具体实施方式
下面将结合本申请实施例中的附图,对本申请实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅是本申请一部分实施例,而不是全部的实施例。基于本申请中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都属于本申请保护的范围。
除非另有定义,本文所使用的所有的技术和科学术语与属于本申请的技术领域的技术人员通常理解的含义相同。本文中在本申请的说明书中所使用的术语只是为了描述具体的实施例的目的,不是在于限制本申请。
其中一个实施例中,提供一种基于共享内存的实时数据分发方法,用于多进程间的数据分发,各进程携带有独立的进程ID,多进程中用于发布数据的为发布进程,用于接收数据的为接收进程,发布进程和接收进程通过数据分发组件完成数据交互,所述数据分发组件基于共享内存实现。
如图2所示,本实施例的所述基于共享内存的实时数据分发方法,包括以下步骤:
步骤S1、发布进程和接收进程加载数据分发组件,数据分发组件申请有多个共享内存通道,每个共享内存通道用于一个数据主题的数据分发。
数据主题用来标识不同数据类型,在发布进程和接收进程加载数据分发组件时,数据分发组件自动完成共享内存初始化,本实施例中,数据分发组件包括通道管理单元和模块ID管理单元,因此共享内存初始化包括通道管理单元初始化和模块ID管理单元初始化。
为支持跨进程数据分发,不同于常见的基于消息的堆内存管理,上述模块ID管理单元和通道管理单元的配置信息并非存储在进程的堆空间而是存储在共享内存中,所有使用该组件的进程都能够直接管理共享内存,省去了消息在不同进程间拷贝传递开销,保证了管理单元信息的一致性。
具体的,本实施例中模块ID管理单元初始化,包括:
首次初始化时,申请模块管理共享内存,设置模块管理共享内存的布局,申请多个全局唯一的模块ID;由于共享内存创建后无法再创建相同的共享内存,因此本实施例在非首次初始化时(即从第二个进程加载时),挂接相应的模块管理共享内存,直接使用已申请的多个全局唯一的模块ID。由于本申请的方法适用于多进程间的数据分发,因此模块ID需要操作系统级全局唯一,模块ID管理单元采用动态申请和动态释放的策略。
如表1所示,模块管理共享内存的布局为内存地址从低到高依次为上次分配的模块ID、进程ID数组和模块状态数组,所述进程ID数组和模块状态数组的大小(即表1中的n)相同且与模块ID的个数相等。
表1模块管理共享内存的布局
进程ID数组记录申请线程的进程ID(含线程ID),在组件初始化时使用操作系统底层函数获取,进程ID可以用来动态判断组件所在程序是否存活。模块状态数组记录模块状态(如是否空闲),上次分配的模块ID暂存最新分配的模块ID,用于快速确定下次分配时最可能的空闲模块ID。
其中进程ID数组以“模块ID-进程ID”的格式进行存储,模块状态数组以“模块ID-模块状态”的格式进行存储。当然也可以按照模块ID的先后顺序仅将进程ID、模块状态存储在进程ID数组、模块状态数组中,建立模块ID与进程ID、模块状态的映射关系。
本实施例中模块ID管理单元初始化后上次分配的模块ID初始化为0,进程ID数组初始化为空,模块状态数组初始化为空闲。
对于每一个加载数据分发组件的进程,模块ID管理单元将为每一进程分配各自的模块ID,并更新上次分配的模块ID、进程ID数组和模块状态数组。从而记录目前加载使用的进程,分配的模块ID用来标识进程的身份,便于查询当前内存资源占用情况。
并且利用模块ID管理单元向进程分配模块ID还可以实现组合模块ID和进程ID的方式区分进程,以便于同个进程实现多次加载订阅的情况。由于同一接收进程能够订阅多个不同的数据主题,但是无法实现针对同一数据主题接收两次相同的数据的情况,因此本实施例设置的模块ID还可以进一步作为区分判断条件,同一进程申请多个模块ID,允许具有不同模块ID的同一进程能够订阅相同的数据主题,即将不同模块ID的同一进程等价为两个不同的进程进行处理,在实现基于最少拷贝次数进行数据传输的同时,还可实现数据的冗余传输,极大提升本申请数据分发的实用性和应用前景。
模块ID管理单元初始化的一个核心的点是如何判断模块管理共享内存是否已经被创建并初始化。由于现代操作系统进程空间是完全隔离的,彼此无法共享变量来判断该模块管理共享内存是否已经创建。因此本实施例根据不同操作系统共享内存创建接口添加特定标识,当该共享内存已经不存在时直接创建共享内存,同时执行初始化过程。当该共享内存已经存在会返回错误信息,提示共享内存已经存在,这时只需要直接挂接已经存在的共享内存,不执行初始化过程。
在模块ID管理单元初始化中,需要动态申请模块ID,模块ID存储在共享内存中,是操作系统级全局唯一ID,在模块初始化时分配,在模块销毁时释放。本实施例为提升模块ID申请注册效率,模块ID使用CPU原子操作指令实现自增与自减操作,避免使用比较耗时的系统信号量和互斥锁等全局锁资源,模块ID申请注册的核心是使用CAS(Compare And Swap)技术实现在不使用互斥锁的情况下修改ID。
具体的,本实施例中通道管理单元初始化包括:
首次初始化时,申请通道管理共享内存,设置通道管理共享内存的布局,申请多个全局唯一的通道ID;非首次初始化时,挂接相应的通道管理共享内存,直接使用已申请的多个全局唯一的通道ID。与模块ID相同的是,本实施例中的通道ID需要操作系统级全局唯一,通道ID管理同样采用动态申请和动态释放的策略,利用通道管理单元管理共享内存通道,可有效提升共享内存通道利用率,优化分配。
如表2所示,通道管理共享内存的布局为内存地址从低到高依次为上次分配的通道ID和通道信息数组,上次分配的通道ID暂存最新分配的通道ID,用于快速确定下次分配时最可能的空闲通道ID。其中通道信息数组的大小与共享内存通道的数量相等,通道信息数组中的每个元素用于记录通道ID以及该共享内存通道的属性,所述共享内存通道的属性包括通道对应的共享内存Key(共享内存的键值)、共享内存大小、信号量Key(信号量的键值)、数据主题ID、模块ID、订阅者(即接收进程)线程ID、订阅者进程ID、通道使用状态和通道清理状态。
表2通道管理共享内存的布局
通道管理单元初始化后所述上次分配的通道ID初始化为0,通道信息数组初始化为默认值,该默认值可以默认为0、空或空闲等,根据实际字段的属性进行选择即可。初始化过程中判断通通道管理共享内存是否已创建的方法与模块ID管理单元初始化中的一致,这里就不在进行详述。
步骤S2、接收进程订阅感兴趣的数据主题,并向所述数据分发组件申请共享内存通道,固定所申请的共享内存通道的数据主题为所订阅的数据主题。
本实施例中接收进程注册订阅感兴趣的数据主题过程实质为建立接收进程对应的模块ID、主题和共享内存通道之间的关联。接收进程和发送进程(简称发布者)之间通过不同的共享内存通道进行数据交互,订阅者和发布者只有建立订阅关系才能收发消息,发布者和订阅者通过数据主题(标识不同数据类型)进行关联。
其中一个实施例中,注册订阅过程如图3所示,具体过程分三个子步骤:
(1)查找接收进程是否已订阅过将要订阅的数据主题。查找过程可以是遍历通道管理单元的所有共享内存通道,核对接收进程订阅的数据主题当中是否存在该数据主题。
(2)若已经订阅过则本次订阅失败;否则接收进程申请共享内存通道,共享内存通道和接收进程存在多对一的对应关系,共享内存通道和数据主题存在一一对应关系,即接收进程可以同时订阅多个数据主题,内部需要同时申请相应个数的共享内存通道。需要说明的是,申请可用共享内存的方法为数据通信领域较为成熟的技术,这里就不再进行详述。
(3)设置共享内存通道的属性。包括设置通道内部队列的共享内存Key、共享内存大小、信号量Key、数据主题ID、模块ID、订阅者线程ID、订阅者进程ID、通道使用状态和通道清理状态等。需要指出的是共享内存Key和信号量Key是系统资源,可能被别的程序占用,不能使用预先分配的策略。动态申请未被占用的共享内存Key和信号量Key方法是:在一定Key值范围内,基于某个Key尝试创建共享内存和信号量,若成功则使用该Key值,若不成功,Key值加一继续创建,循环上述过程直到找到第一个未被使用的Key值。
为了保证数据的正常缓存,在一个实施例中,共享内存通道中包含一个共享内存队列,用于缓存发送进程发送的数据。共享内存队列是基于共享内存的通用缓存队列,该队列与C++标准库的queue接口类似,但内部实现和使用场景完全不同。标准库基于堆内存实现,只能使用在进程内部线程之间;而本申请的共享内存队列基于共享内存实现,可以使用在操作系统内部所有进程之间,也可以使用在进程内部线程之间,支持单生产者单消费者和多生产者单消费者的使用模式,应用范围更广。
本实施例中共享内存队列为FIFO队列,该FIFO队列的实现关键点之一在于解决指针不能跨进程使用的问题。由于每个进程连接共享内存后,虽然物理地址相同,但虚拟地址的起始地址可能不同,类似C++标准库中FIFO队列实现是行不通的,主要原因就在于共享内存指针起始地址不同。为解决这个问题,本实施例提出“相对指针”的概念,即相对共享内存的起始地址的偏移量,相对指针的值为相对共享内存的起始地址的偏移量。
共享内存队列的FIFO布局如表3所示,共享内存队列的列头Head指针记录第一包数据包头的相对指针,共享内存队列的列尾Tail指针记录最后一包数据包头的相对指针,则相对指针应理解为相对于共享内存队列所在共享内存通道的起始地址的偏移量。
表3共享内存队列的FIFO布局
在共享内存队列中,数据入队,列尾Tail指针指向新的数据包的头部;数据出队,列头Head指针指向下一包数据包的头部。对于每个数据包,添加一个固定大小的包节点属性结构,该结构包括下不限于下一节点指针、入队时间、数据包大小和自定义属性包字段。这里的自定义包字段给本实施例的共享内存队列提供了可编辑的可能性,支持自定义字段的写入,提升了整体方法的通用性。
共享内存队列实现数据入队、数据出队和判断队列是否为空队列。数据入队操作检查入队缓存区指针和大小参数,判断入队后列尾指针是否超出内存大小,若未超出内存大小,把数据放入共享内存队列的尾部同时更新列尾指针;若超出内存大小,尝试从列头开始为数据分配空间,若空间充足,数据入队并更新列尾指针返回成功。若空间不足,入队操作返回失败。数据出队操作检查出队缓存区指针和大小参数,判断队列是否为空,若队列为空出队失败,若队列不为空,从队列头部出队数据并拷贝到接收进程,更新接收进程数据大小,更新列头指针,返回出队成功。判断队列是否为空队列通过判断头尾指针是否相等且为NULL值来确定队列是否为空。
本实施例中共享内存队列基于共享内存实现数据收发缓存,数据入队和数据出队使得进程间数据传输只需要进行两次数据拷贝,与常用消息队列数据传输的四次数据拷贝相比,节省了系统资源,降低了数据传输延迟,提高了数据分发效率。
步骤S3、发布进程发布数据到数据所属数据主题对应的所有共享内存通道。
与常见的基于消息路由的发布数据机制不同,本实施例的发送进程发送的数据存储在共享内存中,收发数据的程序不需要通过特定的服务端进行消息中转,减少数据拷贝过程,延迟低、传输性能显著提升。数据发布支持发布者和订阅者的一对多、多对多的数据分发操作,具体子流程如下:
具体的,本实施例中发布进程发布数据到数据所属数据主题对应的所有共享内存通道,主要包括以下原理:
挂接所述通道管理共享内存;基于所述通道管理共享内存获取固定为指定数据主题的所有共享内存通道的通道ID;根据所述通道ID判断对应的通道信息数组中的通道清理状态是否为待清理,清理所有通道清理状态为待清理的共享内存通道;动态挂接剩余的共享内存通道中的共享内存队列;发送数据至每一共享内存队列中。
本实施例中数据的发布不需要关注接收进程,只需发布至指定的数据主题即可,不受系统业务逻辑的限制,灵活性大。需要说明的是,上述实施例中提供的发布原理仅为本实施例提供的一种通用原理,基于该原理还可相应调整步骤,例如在另一实施例中,提供一种发布过程如下。
如图4所示,本实施例中发布进程发布数据到数据所属数据主题对应的所有共享内存通道,包括以下步骤:
(1)挂接通道管理共享内存,为保证所有数据分发组件挂接同一个共享内存,其共享内存Key值和大小是全局唯一确定的。
(2)获取订阅该数据主题的所有接收进程,为提升效率和支持并发操作,每个发布进程单独管理共享内存中的当前通道管理单元,不占用全局互斥锁,多个发布程序操作互不干扰。
(3)判断接收进程是否存活,清理不存活的接收进程占用的共享内存、信号量和通道共享内存队列。
(4)根据接收进程对应的共享内存通道的属性,动态挂接该接收进程所在共享内存队列,共享内存队列有共享内存标识Key、信号量Key和共享内存大小Size决定。
(5)发送数据到接收进程对应的共享内存队列,调用共享内存队列入队接口,数据入队。
(6)若数据发送失败,可分为两种情况:若接收进程已死亡,则放弃本次发送;或者根据订阅时可靠性Qos设置决定是否重新发送数据。
(7)若数据发送成功,继续发送给其他订阅该主题的接收进程对应的共享内存队列。
步骤S4、所述接收进程定时查询所申请的共享内存通道中是否有数据,若有则接收所述共享内存通道中的数据;否则继续定时查询。
具体的,包括以下步骤:
(1)挂接通道管理共享内存,为保证所有进程挂接同一个共享内存,通道管理共享内存Key值和大小是全局唯一确定的。
(2)基于通道管理共享内存获取接收进程所订阅的指定数据主题的共享内存通道的属性。具体为先根据接收进程所订阅的指定数据主题查找对应的通道ID,然后根据通道ID获取对应的共享内存通道的属性。
(3)根据所述共享内存通道的属性挂接共享内存通道中共享内存队列,通道共享内存队列由共享内存标识Key、信号量Key和共享内存大小Size决定。
(4)判断共享内存队列中是否有数据,若有数据则获取数据包大小、数据包发布时间;若无数据,则根据阻塞参数设置与否,分两种情况处理:没有设置阻塞参数,直接返回无数据;有设置阻塞参数,阻塞等待直到数据到来。
(5)根据获取的数据包大小、数据包发布时间从共享内存队列中读取数据。数据从共享内存队列出队,出队参数信息包含数据缓存buf、缓存空间大小、实际数据大小、自定义标识(由发布者和订阅者约定)。
需要说明的是,定时查询的方式即可保证接收进程能够获取所需数据,又可降低接收进程和发送进程之间的交互,且对系统运行压力小,但是除定时查询方式以外,其他常见的数据接收读取方式也在本申请的保护范围内。在其他实施例中,若需要提高数据接收的及时性,接收进程还支持通知机制接收数据,即发送进程发送数据至共享内存通道后主动通知对应的接收进程,接收进程在收到通知后以回调的方式接收共享内存通道中的数据。
在另一实施例中,本申请基于共享内存的实时数据分发方法,还包括接收进程退订数据主题。本实施例中接收进程退订数据主题,如图5所示,包括:
(1)挂接通道管理共享内存。
(2)遍历通道管理共享内存,基于进程ID和将要退订的数据主题查找相应的通道ID;若通道存在,则返回通道ID;若通道不存在,则返回-1。
(3)根据查找到的通道ID从相应通道管理共享内存获取共享内存通道的属性,根据共享内存通道的属性挂接共享内存队列;
(4)设置共享内存通道的属性中的通道使用状态为空闲,释放共享内存队列的资源,标识通道清理状态为待清理,由发布数据过程统一清理。
并且在退订过程中,还会释放模块ID的资源,即还会挂接模块管理共享内存,释放占用的模块ID,并更新模块管理共享内存中的上次分配的模块ID、进程ID数组和模块状态数组。
在另一实施例中,基于共享内存的实时数据分发方法,还包括当所有进程均退订数据主题时,由最后退订的进程销毁数据分发组件,其中销毁数据分发组件包括所述模块ID管理单元销毁和通道管理单元销毁。
其中模块ID管理单元销毁,包括:清理模块管理共享内存,回收模块ID。
所述通道管理单元销毁,包括:清理通道管理共享内存,回收通道ID。
需要指出的是正常情况下,程序退出时会自动执行销毁过程,但在异常情况下,如程序异常退出来不及释放资源,就有可能因资源泄漏导致系统资源耗尽。本方案通过定期资源回收和触发回收两种机制解决上述问题。定期资源回收通过系统定时器周期性的检查僵尸模块,清理僵尸模块资源;触发回收机制在数据发布时触发检查僵尸模块,发现有僵尸模块清理其资源。
本实施例的基于共享内存的实时数据分发方法及装置,通过在共享内存上开辟不同共享内存通道,建立共享内存通道与数据主题的对应关系,发布进程发送数据到特定数据主题上,接收进程从订阅的数据主题上接收数据,通过向主题发布和订阅数据解耦了多个进程之间的关联,从而实现进程间的一对一、一对多和多对多的数据分发;并且不同程序数据收发只有2次内存拷贝且不需要进入操作系统内核态,减少了数据拷贝过程,缩短了数据传输路径,大幅提升数据分发效率和实时性。另外,本发明提供的数据分发组件独立于应用程序业务逻辑,适用于所有单机多个应用软件数据分发的场景,通用性很强。
在另一实施例中,为了便于对本申请数据分发方法的理解,提供一具体实例对本申请的主要思路进行说明。
如图6所示,不同应用程序启动时加载相同的数据分发组件(接口),通过接口调用实现不同应用程序间的数据分发。程序A、程序B、程序C、程序D加载相同的数据分发组件,假定程序B和程序D订阅数据主题1,在订阅过程中会自动申请相应共享内存通道,当程序A发布数据到数据主题1时,数据被发布到程序B和程序D的共享内存通道中,从而程序B和程序D能够从共享内存通道接收到标识为数据主题1的数据;同理,程序C发布数据主题1数据到程序B和程序D的共享内存通道,程序B和程序D接收到标识为数据主题1的数据,不同的共享内存通道完成不同程序间的数据转发。数据发布程序不需要了解其他程序的信息只关注主题,该方法降低了应用程序间耦合性,为复杂应用系统实时数据分发和应用程序模块化集成提供了一种通用解决方案。
在另一实施例中,还提供一种基于共享内存的实时数据分发装置。如图7所示,本实施例的装置包括处理器、存储器以及存储在存储器中并可在处理器中运行的计算机程序,处理器执行计算机程序时实现上述任一实施例中的基于共享内存的实时数据分发方法中的步骤。
本实施例中所称处理器可以是中央处理单元(CPU,central processing unit),还可以是其他通用处理器,如数字信号处理器(DSP,digital signal processor)、专用集成电路(ASIC,Application Specific Integrated Circuit)和现场可编程门阵列(FPGA,Field Programmable Gate Array)等;存储器用于存储计算机程序以及装置相关的其他程序和数据,存储器可以是内部存储单元,例如硬盘或内存,也可以是外部存储设备,例如插接式硬盘、智能存储卡、安全数字卡、闪存卡等,进一步的存储器可以既包括内存存储单元也包括外部存储设备;计算机程序可以被分割成一个或多个模块/单元存储在存储器中,并有处理器执行,以完成本申请。一个或多个模块/单元可以是能够完成特定功能的一系列计算机程序指令段,该指令段用于描述计算机程序的执行过程。
应该理解的是,虽然流程图中的各个步骤按照箭头的指示依次显示,但是这些步骤并不是必然按照箭头指示的顺序依次执行。除非本文中有明确的说明,这些步骤的执行并没有严格的顺序限制,这些步骤可以以其它的顺序执行。而且,图中的至少一部分步骤可以包括多个子步骤或者多个阶段,这些子步骤或者阶段并不必然是在同一时刻执行完成,而是可以在不同的时刻执行,这些子步骤或者阶段的执行顺序也不必然是依次进行,而是可以与其它步骤或者其它步骤的子步骤或者阶段的至少一部分轮流或者交替地执行。
以上所述实施例的各技术特征可以进行任意的组合,为使描述简洁,未对上述实施例中的各技术特征所有可能的组合都进行描述,然而,只要这些技术特征的组合不存在矛盾,都应当认为是本说明书记载的范围。
以上所述实施例仅表达了本申请的几种实施方式,其描述较为具体和详细,但并不能因此而理解为对发明专利范围的限制。应当指出的是,对于本领域的普通技术人员来说,在不脱离本申请构思的前提下,还可以做出若干变形和改进,这些都属于本申请的保护范围。因此,本申请专利的保护范围应以所附权利要求为准。
- 一种基于共享内存的实时数据分发方法及装置
- 基于共享内存实现变电站装置信息实时传输的系统及方法