jeudi 4 février 2016

sharing a custom struct using boost::interprocess

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;
    }
};

Aucun commentaire:

Enregistrer un commentaire