sharing a custom struct using boost::interprocess

心不动则不痛 提交于 2019-12-11 10:18:32

问题


I need to allocate a user defined struct in shared memory using boost's managed_shared_memory but I am not sure how to go about this correctly. It appears that the key to getting this to work correctly is the use of custom allocators. I have successfully been able to make this work with a simple POD uint64_t type, however things become more involved when I try to put more complex types in shared memory. An example of a simple struct I would like to place in shared memory would be something along the following lines:

struct SharedMemStruct {
    explicit SharedMemStruct() = default;
    explicit SharedMemStruct(
        const bool bField0,
        const std::string& rField1,
        const uint32_t& rField2)
        : mField0(bField0)
        , mField1(rField1)
        , mField2(rField2)
    {}
    bool mField0;
    std::string mField1;
    uint32_t mField2;
};

With the POD type I successfully initialized the shared memory as follows (placing the 64 bit shared value in a named area called "FaultReport" that can be shared with another process.

        // Remove shared memory on construction and destruction
        struct shm_remove {
            shm_remove() { shared_memory_object::remove("albfd_shared_mem"); }
            ~shm_remove() { shared_memory_object::remove("albfd_shared_mem"); }
        } remover;

        // create a new shared memory segment 2K size
        managed_shared_memory managed_shm(create_only, "albfd_shared_mem", 2048);

        // construct a FaultReport - default to no faults
        auto pFaultWrapper = managed_shm.construct<UtlSharedIPCWrapper<uint64_t>>("FaultReport")(0);

In another process that requires access to the above FaultReport, it is a simple matter as follows:

    // create a new shared memory segment 2K size
    managed_shared_memory managed_shm(open_only, "albfd_shared_mem");

    // shared memory must exist in
    shared_memory_object shm(open_only, "albfd_shared_mem", read_write);

    // lookup the FaultReport shared memory wrapper
    auto pFaultReport = managed_shm.find<UtlSharedIPCWrapper<uint64_t>>("FaultReport").first;

    // initialize the bit-set from the current shared memory fault report
    std::bitset<64> bitSet(pFaultReport->getSharedData());

The UtlSharedIPCWrapper provides me safe access to its data type T

template<typename T>
struct UtlSharedIPCWrapper {
private:
    using upgradable_mutex_type = boost::interprocess::interprocess_upgradable_mutex;

    mutable upgradable_mutex_type mMutex;
    /*volatile*/ T mSharedData;
public:
    // explicit struct constructor used to initialize directly from existing memory
    explicit UtlSharedIPCWrapper(const T& rInitialValue)
        : mSharedData(rInitialValue)
    {}

    T getSharedData() const {
        boost::interprocess::sharable_lock<upgradable_mutex_type> lock(mMutex);
        return mSharedData;
    }

    void setSharedData(const T& rSharedData) {
        boost::interprocess::scoped_lock<upgradable_mutex_type> lock(mMutex);
        // update the shared data copy mapped - scoped locked used if exception thrown
        // a bit like the lock guard we normally use
        this->mSharedData = rSharedData;
    }
};

EDIT: So after doing a bit of experimentation - in particular after realizing that my SharedIPCStruct contains multiple variable string fields (and therefore effectively requires pointers or some nature), I rewrote the struct in the header file and have shown it below. The key here seems to be having some sort of special stl replacement string that uses the boost's shared memory model. To this end, I defined the following for the string type that needed to be stored in my structure:

using char_allocator = boost::interprocess::managed_shared_memory::allocator<char>::type;
using shm_string = boost::interprocess::basic_string<char, std::char_traits<char>, char_allocator>;

One of these char_allocators is passed as the last argument into my custom struct to assist with converting normal std::strings to these new shm_strings. I don't really understand what is going under the covers here but it seemed to work - stepping through boost code is pretty much template nonsense at this point.

#pragma once

// SYSTEM INCLUDES
#include <string>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
using char_allocator = boost::interprocess::managed_shared_memory::allocator<char>::type;
using shm_string = boost::interprocess::basic_string<char, std::char_traits<char>, char_allocator>;

// FORWARD DECLARATIONS

struct SharedIPCStruct {
    explicit SharedIPCStruct (
        const std::string& rString1,
        const std::string& rString2,
        const uint32_t& rHashValue,
        const std::string& rString3,
        const char_allocator& ca)
        : mField1(rString1.cbegin(), rString1.cend(), ca)
        , mField2(rString2.cbegin(), rString2.cend(), ca)
        , mField3(rHashValue)
        , mField4(rString3.cbegin(), rString3.cend(), ca)
    {}
    // note these are not std::strings
    shm_string mField1;
    shm_string mField2;
    uint32_t mField3;
    shm_string mField4;
};

Now with all this in place, allocating the shared memory structure was as simple as this:

        char_allocator ca(managed_shm.get_allocator<char>());

        // Create an object of SharedIPCStruct initialized to {"", "", 0, "", ca}
        auto *pSHMStruct= managed_shm.construct<SharedIPCStruct>
            ("SharedIPCStruct")    // name of the object
            ("", "", 0, "", ca);   // ctor args

This works well and in another process I can perform the counterpart to search for the existing SharedIPCStruct with the following

    // lookup the SharedIPCStruct
    auto *pSHMStruct = managed_shm.find<SharedIPCStruct>("SharedIPCStruct").first;

The problem still remains however that I cannot construct a UtlSharedIPCWrapper<SharedIPCStruct> in shared memory. I wanted to do this to provide safe access to the SharedIPCStruct.

This compiles and runs due to the fact that the template argument type for the UtlSharedIPCWrapper is a POD type:

auto pFaultWrapper = managed_shm.construct<UtlSharedIPCWrapper<uint64_t>>("FaultReport")(0);    

However, I replace

        // Create an object of SharedIPCStruct initialized to {"", "", 0, "", ca}
        auto *pSHMStruct= managed_shm.construct<SharedIPCStruct>
            ("SharedIPCStruct")    // name of the object
            ("", "", 0, "", ca);   // ctor args

with the templatized wrapper like I did above for the POD type for that wrapping a custom data structure

        // Create an object of SharedIPCStruct initialized to {"", "", 0, "", ca}
        auto *pSHMStruct= managed_shm.construct<UtlSharedIPCWrapper<SharedIPCStruct>>
            ("SharedIPCStruct")    // name of the object
            ("", "", 0, "", ca);   // ctor args

I get a ton of unintelligible errors. Can someone explain what is going on here and how I should write this correctly in order to use my wrapper. Also what is general rule (if any) that one has to apply to use custom data structures in shared memory? I figured out that std::strings could not be used but what about floats, etc and other types.

 main.cpp
1>c:\main\extlibs\boost_1_60_0\boost\interprocess\detail\named_proxy.hpp(83): error C2661: 'UtlSharedIPCWrapper<SharedIPCStruct>::UtlSharedIPCWrapper': no overloaded function takes 5 arguments
1>  c:\main\extlibs\boost_1_60_0\boost\interprocess\detail\named_proxy.hpp(71): note: see reference to function template instantiation 'void boost::interprocess::ipcdetail::CtorArgN<T,false,const char (&)[1],const char (&)[1],int,const char (&)[1],char_allocator &>::construct<0,1,2,3,4>(void *,boost::interprocess::ipcdetail::false_,const boost::container::container_detail::index_tuple<0,1,2,3,4> &)' being compiled
1>          with
1>          [
1>              T=UtlSharedIPCWrapper<SharedIPCStruct>
1>          ]
1>  c:\main\extlibs\boost_1_60_0\boost\interprocess\detail\named_proxy.hpp(71): note: see reference to function template instantiation 'void boost::interprocess::ipcdetail::CtorArgN<T,false,const char (&)[1],const char (&)[1],int,const char (&)[1],char_allocator &>::construct<0,1,2,3,4>(void *,boost::interprocess::ipcdetail::false_,const boost::container::container_detail::index_tuple<0,1,2,3,4> &)' being compiled
1>          with
1>          [
1>              T=UtlSharedIPCWrapper<SharedIPCStruct>
1>          ]
1>  c:\main\extlibs\boost_1_60_0\boost\interprocess\detail\named_proxy.hpp(68): note: while compiling class template member function 'void boost::interprocess::ipcdetail::CtorArgN<T,false,const char (&)[1],const char (&)[1],int,const char (&)[1],char_allocator &>::construct_n(void *,size_t,size_t &)'
1>          with
1>          [
1>              T=UtlSharedIPCWrapper<SharedIPCStruct>
1>          ]
1>  c:\main\extlibs\boost_1_60_0\boost\interprocess\detail\named_proxy.hpp(128): note: see reference to class template instantiation 'boost::interprocess::ipcdetail::CtorArgN<T,false,const char (&)[1],const char (&)[1],int,const char (&)[1],char_allocator &>' being compiled
1>          with
1>          [
1>              T=UtlSharedIPCWrapper<SharedIPCStruct>
1>          ]
1>  c:\main\dlmu\albfd-0339.1\src\albfd\main.cpp(224): note: see reference to function template instantiation 'T *boost::interprocess::ipcdetail::named_proxy<boost::interprocess::segment_manager<CharType,MemoryAlgorithm,IndexType>,T,false>::operator ()<const char(&)[1],const char(&)[1],int,const char(&)[1],char_allocator&>(const char (&)[1],const char (&)[1],int &&,const char (&)[1],char_allocator &) const' being compiled
1>          with
1>          [
1>              T=UtlSharedIPCWrapper<SharedIPCStruct>,
1>              CharType=char,
1>              MemoryAlgorithm=boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,ptrdiff_t,uintptr_t,0>,0>,
1>              IndexType=boost::interprocess::iset_index
1>          ]
1>  c:\main\dlmu\albfd-0339.1\src\albfd\main.cpp(224): note: see reference to function template instantiation 'T *boost::interprocess::ipcdetail::named_proxy<boost::interprocess::segment_manager<CharType,MemoryAlgorithm,IndexType>,T,false>::operator ()<const char(&)[1],const char(&)[1],int,const char(&)[1],char_allocator&>(const char (&)[1],const char (&)[1],int &&,const char (&)[1],char_allocator &) const' being compiled
1>          with
1>          [
1>              T=UtlSharedIPCWrapper<SharedIPCStruct>,
1>              CharType=char,
1>              MemoryAlgorithm=boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,ptrdiff_t,uintptr_t,0>,0>,
1>              IndexType=boost::interprocess::iset_index
1>          ]

来源:https://stackoverflow.com/questions/35204104/sharing-a-custom-struct-using-boostinterprocess

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!