C++ 模块间共享内存

C++ 模块间共享内存,c++,memory,module,C++,Memory,Module,我想知道如何在不同的程序模块之间共享一些内存——比如说,我有一个主应用程序(exe),然后是一些模块(dll)。它们都链接到同一个静态库。这个静态库将有一些管理器,提供各种服务。我想要实现的是,让这个管理器在所有应用程序模块之间共享,并在库初始化期间透明地执行此操作。 在进程之间,我可以使用共享内存,但我只希望在当前进程中共享。 你能想出一些跨平台的方法吗?可能使用boost库,前提是它们提供了一些实现这一点的工具 我现在能想到的唯一解决方案是使用各个操作系统的共享库,所有其他模块都将在运行时链

我想知道如何在不同的程序模块之间共享一些内存——比如说,我有一个主应用程序(exe),然后是一些模块(dll)。它们都链接到同一个静态库。这个静态库将有一些管理器,提供各种服务。我想要实现的是,让这个管理器在所有应用程序模块之间共享,并在库初始化期间透明地执行此操作。 在进程之间,我可以使用共享内存,但我只希望在当前进程中共享。 你能想出一些跨平台的方法吗?可能使用boost库,前提是它们提供了一些实现这一点的工具

我现在能想到的唯一解决方案是使用各个操作系统的共享库,所有其他模块都将在运行时链接到该库,并将管理器保存在其中

编辑: 为了澄清我的实际需要:

  • 我需要找出是否已经创建了共享管理器(下面的答案已经提供了一些方法)
  • 获取指向管理器的指针(如果存在),或者将指针设置在新创建的管理器对象的某处

  • 您可以使用
    boost::进程间
    
    
    在Windows上,您可以使用#pragma:

    在DLL中创建一个共享段,供所有进程共享。仅从当前进程使用,不需要设计任何特殊的函数或结构

    即使没有任何功能,您也可以这样做,但定义一组提供对共享数据访问的功能更安全、跨平台友好。这些功能可以通过通用静态库来实现

    我认为,这个设置唯一关心的是:“谁将拥有这些数据?”。共享数据必须存在且仅存在一个所有者

    有了这些基本思想,我们可以像这样绘制API:

    IsSharedDataExist     // check whether of not shared data exist
    
    CreateSharedData      // create (possibly dynamically) shared data
    
    DestroySharedData     // destroy shared data
    
    ... various data access API ...
    

    或C++类,以单模式为宜。


    更新

    我很困惑。真正的问题可以定义为“如何在一个静态库中实现一个单例类,该库将以平台无关的方式与多个动态加载库(将在同一进程中使用)链接”

    我认为,基本的想法没有太大的不同,但确保单身是真正的单身是这个设置的附加问题

    为此,可以使用Boost.Interprocess

    #include <boost/config.hpp>
    #include <boost/interprocess/sync/named_mutex.hpp>
    ...
    boost::interprocess::named_mutex* singleton_check = 0;
    
    // in the Create function of the singleton
    try {
        singleton_check = new boost::interprocess::named_mutex(boost::interprocess::create_only, "name_of_the_mutex" );
        // if no exception throw, this is the first time execution
    }
    catch (...)
    {
    }
    
    #包括
    #包括
    ...
    boost::进程间::命名的\u互斥*单例\u检查=0;
    //在singleton的Create函数中
    试一试{
    singleton_check=new boost::interprocess::named_mutex(boost::interprocess::create_only,“name_of_mutex”);
    //如果没有异常抛出,这是第一次执行
    }
    捕获(…)
    {
    }
    
    释放命名的\u互斥体非常简单,只需
    delete singleton\u check


    更新#2

    另一个建议

    我认为,我们不应该将共享数据放在公共静态库中。如果我们不能确保数据的全局唯一性,那么这不仅是棘手的依赖于平台的实现问题,而且也是内存和全局资源的浪费

    如果您更喜欢静态库实现,那么应该创建两个静态库。一个用于共享数据的服务器/创建者,一个用于共享数据的用户。服务器库定义并提供对单例的访问。客户端库提供各种数据访问方法


    这实际上与没有静态库的单例实现相同。

    我认为您需要共享库的帮助才能以任何可移植的方式实现这一点。它不一定需要知道模块之间共享的对象的任何信息,它只需要提供一些从键(可能是字符串)到指针的全局可访问映射

    但是,如果您愿意调用OS API,这是可行的,并且我认为您可能只需要两个OS特定部分的实现(一个用于Windows DLL和GetProcAddress,一个用于使用dlopen的OS)

    当每个模块加载时,它遍历以前加载的模块列表,查找任何导出特殊命名函数的模块。如果它找到一个(任何,不管是哪一个,因为不变量是所有完全加载的模块都知道公共对象),它将从先前加载的模块中获取公共对象的地址,然后增加引用计数。如果找不到,则分配新数据并初始化引用计数。在模块卸载期间,如果引用计数达到零,它将递减引用计数并释放公共对象

    当然,对公共对象使用OS分配器是必要的,因为虽然不太可能,但它可能是从不同的库中释放的,而不是从第一次加载它的库中释放的。这也意味着公共对象不能包含任何虚拟函数或指向不同模块段的任何其他类型的指针。必须使用操作系统进程范围的分配器动态分配其所有资源。对于libc++是共享库的系统来说,这可能不是什么负担,但您说过您正在静态链接CRT

    Win32中需要的函数包括
    EnumProcessModules
    GetProcAddress
    HeapAlloc
    ,和
    HeapFree
    GetProcessHeap
    GetCurrentProcess

    考虑到所有因素,我认为我会坚持将公共对象放在它自己的共享库中,该库利用加载程序的数据结构来查找它。否则你就是在发明加载器。即使CRT静态链接到多个模块中,这也会起作用,但我认为您正在为自己设置ODR冲突。要特别注意保持公共数据舱。

    根据我所见,在模块之间共享数据的方法只有两种

  • 使用data_seg pragma
  • 使用共享内存 正如有人指出的,共享段只适用于两个仪表