• 构建自己的C/C++插件开发框架(四)——核心层设计和实现


    上面一篇文章大致描述了一下插件开发框架整体结构。这篇描述一下核心层的设计和实现。

    至于核心层的设计,我想借鉴 一下微内核的思想。核心层只负责实现下面几个功能:

    1、 插件的加载,检测,初始化。

    2、 服务的注册。

    3、 服务的调用。

    4、 服务的管理。

    插件的加载,检测,初始化

    插件的加载利用linux共享库的动态加载技术。具体的方法可以看一下IBM网站的一篇资料《Linux 动态库剖析》

    服务的注册

    服务的注册与调用采用表驱动的方法。核心层中维护一个服务注册表。

    //插件间交互消息类型
    typedef enum __Service_Type
    {
        Service_Max,
    }Service_Type;
    //插件用于和其他插件通信接口函数,由插件提供。
    typedef PRsp_Ele_Stream (*PF_Invoke_Service_Func)(PReq_Ele_Stream pele_str);
    //驱动表
    typedef PF_Invoke_Service_Func Service_Drive_Table[Service_Max];

    驱动表是一个数组,下标为插件间交互消息类型,成员为插件提供的接收的消息处理函数,由插件初始化的时候,调用插件框架的的注册函数注册到驱动表。

    插件的初始化实现为:
    //插件用于注册处理的消息类型的函数,由插件框架提供。
    typedef RET_RESULT (*PF_Service_Register_Func)(Service_Type service_type);
    //插件用于和其他插件通信接口函数,由插件框架提供。
    typedef PRsp_Ele_Stream (*PF_Invoke_Service_Func)(PReq_Ele_Stream pele_str);
    //插件回复响应函数。插件收到异步请求后,处理完成后,发送响应消息给请求的插件。由插件框架提供
    typedef void (*PF_Send_Response_Func)(PRsp_Ele_Stream pele_str);
    //初始化插件信息
    typedef struct Plugin_Init_St
    {
        PF_Service_Register_Func register_func;//服务注册函数,要注册一系列的枚举值。插件可以处理的服务枚举值
        PF_Invoke_Service_Func invoke_serv_func;//和其他组件交互时,调用的用于和其他组件交互的函数。发送请求消息。
        PF_Send_Response_Func send_rsp_func;//再设计一个回复响应消息的接口。收到异步请求后,处理完毕后通知请求模块处理结果。
    } Plugin_Init_St, *PPlugin_Init_St;
    //初始化插件函数,类似于构造函数。由插件提供,供插件框架加载插件时初始化插件使用。
    void PF_Init_Plugin(PPlugin_Init_St pinit_info);

          插件在函数PF_Init_Plugin中调用函数register_func来注册插件要处理的消息类型。

    服务的调用
    //信元结构体
    typedef struct Ele_St
    {
        Ele_Tag tag;
        Ele_Length len;
        Ele_Value  value;
        PEle_St next;
    }Ele_St, *PEle_St;
    //请求消息,信元流格式。
    typedef struct Req_Ele_Stream
    {
        Plugin_ID src_id;//源插件id
        Service_Type req_type;//请求类型
        PEle_St ele;
    } Req_Ele_Stream, *PReq_Ele_Stream;
    //响应消息,信元流格式。
    typedef struct Rsp_Ele_Stream
    {
        Plugin_ID dest_id;//目的插件id
        Service_Type req_type;//响应对应的请求的类型。
        Execute_Result result;//记录执行结果
        Execute_Reason reason;//记录执行结果的原因
        PEle_St ele;
    } Rsp_Ele_Stream, *PRsp_Ele_Stream;
    //接收插件调用服务请求函数,由插件提供,入参为请求信元流。返回值为响应信元流,用于同步请求处理。
    PRsp_Ele_Stream PF_Receive_Invoke_Proc(PReq_Ele_Stream pele_str);
    //插件收到响应消息的处理入口函数,由插件提供。如此为响应信元流。
    void PF_Receive_Rsponse_Porc(PRsp_Ele_Stream pele_str);

    插件间的依赖关系是通过信元流来实现的。至于信元流的使用在我的另一篇博客《使用信元流(TLVStream)规范、简化模块(C/C++)间交互 》 中有描述。插件对外的接口都是统一的。

    如果插件要和其他的插件通信,则调用PF_Init_Plugin函数的传递的服务调用接口: invoke_serv_func。插件框架根据信元流的类型,查找驱动表,找到对应的服务接收函数。插件用函数 PF_Receive_Invoke_Proc接受其他插件的请求,此函数是插件想插件框架主动注册到驱动表的。

    如果服务时同步的,这直接通过此函数返回,返回的信息在响应信元流中。如果是异步的请求,这插件在处理完成后,通过 send_rsp_func函数来发送响应。

    插件的卸载
    //卸载插件时调用的函数,类似于析构函数。由插件提供,供插件框架卸载插件时调用。
    void PF_Destroy_Func();

  • 相关阅读:
    BZOJ-3211花神游历各国 并查集+树状数组
    HDU-1754I Hate It 线段树区间最值
    POJ-2777Count Color 线段树+位移
    BZOJ-1012[JSOI2008]最大数maxnumber 线段树区间最值
    HDU-1394 Minimum Inversion Number 线段树+逆序对
    HDU-1698 JUST A HOOK 线段树
    学习笔记 --- 线段树
    poj 2155 Matrix---树状数组套树状数组
    hdu 1166 敌兵布阵--BIT
    学习笔记 BIT(树状数组)
  • 原文地址:https://www.cnblogs.com/chgaowei/p/1581999.html
Copyright © 2020-2023  润新知