在Ada95中跨共享库/对象共享数据

时间:2012-09-07 20:23:39

标签: c++ shared-libraries ada gnat

好的,这将是一个很长的,我提前为此道歉。 =)

我需要指出的是,由于保密原因,此处使用的代码与实际生产代码并不完全匹配,但是用于说明问题,一些经过测试的解决方案以及促进讨论。在概念层面上,虽然所有内容都已被删除和简化,但它足够相似。数据保护虽然在现实中是必要的,但在这里却被忽略了。

问题

我们有一个共享对象'data_provider',它是从Ada代码生成的。 Data_provider有一个内部数据记录,我们需要从许多共享对象访问'data_user'1到n,也是从(不同的)Ada代码生成的。这些共享包含类型defs的Ada规范,但实际上数据需要在共享对象边界之间共享,最好不要进行不必要的复制(有效;估计和基准测试)性能原因。

这些共享对象通过libdl链接到c ++主程序(此处称为'wrapper'),无论是编译时还是运行时(这还不是一成不变的),因此解决方案需要工作无论哪种方式。我应该补充一点,如果可以从c ++端检查数据也是有益的,即使我们没有可用的完整类型def。

代码可能需要通过Ada95编译,尽管-05 可能可以工作。 -12不在桌面上。平台是RHEL5上的GNAT。

我试过的东西

目前,“工作”解决方案是简单地获取数据记录的地址,将其传递给包装器,将其传递给data_user对象,在那里转换地址>访问,并将指针数据复制到内部对象。这是下面的示例代码中实现的方法。但是额外的副本可能在性能方面存在问题。

另一个“有效”的测试方法是简单地让data_provider导出变量,data_users导入变量,但这要求它们在编译时都被链接,并且它还会全局公开数据,这让我觉得很脏,更不用说它很脆弱了。

我相信for data'address use addr条款需要在详细时间知道地址,因此不起作用..?

其他一些事情已被尝试并被丢弃,但我现在暂时离开他们。

我希望结合下面的代码足以得到一些建议;我听见了。如果有任何需要澄清的话,请索取。 =)

我其实很希望我只是愚蠢而且在这里遗漏了一些明显的东西。我确实意识到,在Ada或其他方面,整个混乱并不完全遵循良好的编码习惯,但我仍然有点坚持。

wrapper.cpp

extern "C"  {
    void update_data( int fa, int fb );
    int get_address( void );
    void set_address( int addr );
    void handle_new_data( void );
}

int main( int argc, char** argv ) {
    int addr;
    addr = get_address();
    set_address( addr );
    for (int i = 0; i < 42; i++) {
        update_data( i, -i );
        handle_new_data();
    }
}

data_types.ads

package data_types is

    -- dummy data type
    -- SIMPLIFIED from actual use case
    type data_t is
        record
            field_a : integer := 16#c0ffee#;
            field_b : integer := 16#c0ffee#;
        end record;

    for data_t use
        record
            field_a at 0 range 0..31;
            field_b at 4 range 0..31;
        end record;

    type data_t_ptr is access data_t;

end data_types; 

data_provider.ads

with    system,
        data_types;
use     system,
        data_types;

package data_provider is
    -- update internal data structure
    -- SIMPLIFIED from actual use case
    procedure update_data
        (   fa : in integer;
            fb : in integer );
    pragma export_procedure
    (   internal => update_data,
        external => "update_data" );


    -- return address to record containing data
    function get_address return system.address;
    pragma export_function
    (   internal => get_address,
        external => "get_address" );

    -- 'dummy' data; this needs to be passed to data_user
    data : data_t;

end data_provider;    

data_provider.adb

with    system;
use     system;

package body data_provider
is
    procedure update_data
        (   fa : in integer;
            fb : in integer )
    is
    begin
        data.field_a := fa;
        data.field_b := fb;
    end ;


    function get_address return system.address
    is
    begin
        return data'address;
    end;

end data_provider; 

data_user.ads

with    system,
        data_types;
use     system,
        data_types;

package data_user
is
    -- set address for the data record
    procedure set_address
        (   addr : system.address );
    pragma export_procedure
        (   internal => set_address,
            external => "set_address" );

    -- use the new data in internal data structure
    -- SIMPLIFIED from actual use case
    procedure handle_new_data;
    pragma export_procedure
        (   internal => handle_new_data,
            external => "handle_new_data" );

    -- 'dummy' data; this needs to be passed from data_provider
    data : data_t;

end data_user;

data_user.adb

with    system,
        unchecked_conversion,
        data_types;
use     system,
        data_types;

package body data_user
is

    function to_ptr is new unchecked_conversion
        (   source => system.address,
            target => data_t_ptr );

    -- set address for the data record
    procedure set_address
        (   addr : system.address )
    is
        ptr : data_t_ptr;
    begin
        ptr := to_ptr( addr );
        data := ptr.all;
    end;

    -- use the new data in internal data structure
    -- SIMPLIFIED from actual use case
    procedure handle_new_data
    is
    begin
        null;
    end;

end data_user;

TLDR

用Ada编写并从C ++外部调用的多个共享库需要访问存储在Ada记录中的相同数据,最好不要复制。我该怎么做?

1 个答案:

答案 0 :(得分:4)

将数据复制到用户的唯一位置是Data_User.Set_Address。致Data_Provider.Update_Data的电话会更改Data_Provider中的副本,但不会对任何用户产生任何影响。

为什么不让Set_Address存储指针,然后Handle_New_Data读取它?

package data_user
is

   --  as before

   data_ptr : data_t_ptr;

end data_user;

.......
package body data_user
is

   .....

   -- set address for the data record
   procedure set_address
     (   addr : system.address )
   is
   begin
      data_ptr := to_ptr( addr );
   end;

   procedure handle_new_data
   is
   begin
      -- work with data_ptr.all
   end;

end data_user;

顺便说一句,您应该使用System.Address_To_Access_Conversions而不是Unchecked_Conversion来完成这项工作。