Sharing memory between modules

前端 未结 4 1472
南方客
南方客 2020-12-13 22:36

I was wondering how to share some memory between different program modules - lets say, I have a main application (exe), and then some module (dll). They both link to the sam

相关标签:
4条回答
  • 2020-12-13 22:47

    You can use boost::interprocess http://www.boost.org/doc/libs/1_45_0/doc/html/interprocess.html and on Windows you can create a shared segment in your DLL that will be shared by all processes using #pragma's: http://www.codeproject.com/KB/DLL/data_seg_share.aspx

    0 讨论(0)
  • 2020-12-13 22:55

    I think you're going to need assistance from a shared library to do this in any portable fashion. It doesn't necessarily need to know anything about the objects being shared between modules, it just needs to provide some globally-accessible mapping from a key (probably a string) to a pointer.

    However, if you're willing to call OS APIs, this is feasible, and I think you may only need two implementations of the OS-specific part (one for Windows DLLs and GetProcAddress, one for OSes which use dlopen).

    As each module loads, it walks the list of previously loaded modules looking for any that export a specially-named function. If it finds one (any, doesn't matter which, because the invariant is that all fully-loaded modules are aware of the common object), it gets the address of the common object from the previously loaded module, then increments the reference count. If it's unable to find any, it allocates new data and initializes the reference count. During module unload, it decrements the reference count and frees the common object if the reference count reached zero.

    Of course it's necessary to use the OS allocator for the common object, because although unlikely, it's possible that it is deallocated from a different library from the one which first loaded it. This also implies that the common object cannot contain any virtual functions or any other sort of pointer to segments of the different modules. All its resources must by dynamically allocated using the OS process-wide allocator. This is probably less of a burden on systems where libc++ is a shared library, but you said you're statically linking the CRT.

    Functions needed in Win32 would include EnumProcessModules, GetProcAddress, HeapAlloc, and HeapFree, GetProcessHeap and GetCurrentProcess.

    Everything considered, I think I would stick to putting the common object in its own shared library, which leverages the loader's data structures to find it. Otherwise you're re-inventing the loader. This will work even when the CRT is statically linked into several modules, but I think you're setting yourself up for ODR violations. Be really particular about keeping the common data POD.

    0 讨论(0)
  • 2020-12-13 22:55

    For use from the current process only, you don't need to devise any special function or structure.

    You could do it even without any function but it is more safe and cross platform friendly to define set of functions providing access to the shared data. And these functions could be implemented by the common static library.

    I think, only concern of this setup is that: "Who will own the data?". There must exist one and only one owner of the shared data.

    With these basic idea, we could sketch the API like this:

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

    Or C++ class with the Singleton pattern will be appropriate.


    UPDATE

    I was confused. Real problem can be defined as "How to implement a Singleton class in a static library that will be linked with multiple dynamic loading library (will be used in the same process) in platform independent way".

    I think, basic idea is not much different but make sure the singleton is the really single is the additional problem of this setup.

    For this purpose, you could employ 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 (...)
    {
    }
    

    Freeing the named_mutex is as simple as delete singleton_check.


    UPDATE#2

    Another suggestion.

    I think, we should not place shared data in the common static library. If we can not ensure globally unique data, it is not only tricky platform dependent implementation problems but also waste of memory and global resources.

    If you prefer static library implementation you should make two static libraries. One for the server/creator of the shared data, one for users of that shared data. Server library define and provide access to the Singleton. Client library provide various data access method.

    This is effectively same as the Singleton implementation without static libraries.

    0 讨论(0)
  • 2020-12-13 22:57

    As per MSDN I see there are only two ways to share data between modules

    1. Using data_seg pragma
    2. Use shared memory.

    As someone pointed out Shared Segment works only for two instances of the same dll so we are left with only one choice to use Memory-Mapped Files technique.

    0 讨论(0)
提交回复
热议问题