1

I have the following UtlSharedIPCWrapper template class that I created access a user defined type that is placed in inter-process memory.

Normally this class is used with a simple type for example:

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

and this works well, however I recently had the need to use a boost shared memory map collection (boost::interprocess::map) as a template argument) as in:

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>;
using KeyType = shm_string;
using ValueType = std::pair<const KeyType, shm_string>;
using ShmemAllocator = boost::interprocess::allocator<ValueType, boost::interprocess::managed_shared_memory::segment_manager>;
using SharedMemoryMap = boost::interprocess::map<shm_string, shm_string, std::less<KeyType>, ShmemAllocator>;

...

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

//Initialize the shared memory STL-compatible allocator
ShmemAllocator alloc(managed_shm.get_segment_manager());

auto pSharedNVPairs = managed_shm.find<UtlSharedIPCWrapper<
    SharedMemoryMap>>("NameValuePairs").first;

my question is how can I change the template class definition below to pass collection::value types's as parameters instead of separately reading the entire map as one operation via pSharedNVPairs->getSharedData() updating the temporary map and writing it back to shared memory again via pSharedNVPairs->setSharedData(*pSharedNVPairs). I know that this will be different for types that are not collections and thefore some template metaprogramming magic will have to be performed that does selective enable if etc,., but I would like to have a method added to my class something along the lines of

// I don't know the correct signature here
void setSharedDataValue(const T::value_type& rSharedDataValue) {
    boost::interprocess::scoped_lock<upgradable_mutex_type> lock(mMutex);
    ... not sure what to do here to update the collection
}

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 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;
    }
};
ildjarn
  • 62,044
  • 9
  • 127
  • 211
johnco3
  • 2,401
  • 4
  • 35
  • 67
  • I have a suspicion you really want to ask a - much - different question - in which case, please clarify by extending the code sample to be self-containted – sehe Feb 08 '16 at 06:55
  • @sehe I agree that the question might be a little vague, however I do have the 2 different cases that I wanted to get working above, one that takes a simple integral type and the other that is a collection. I would like to know how to use template magic to make the appropriate template specializations work – johnco3 Feb 08 '16 at 14:39
  • @Sehe using GCC 4.9.1 I get the error below. It makes me think that I really need some std::enable_if machinery to effectively comment the whole method out if the instantiation of the template is not integral or more specifically of type container - what do you think? - I'm not sure how to do this though. Here is an abbreviated compiler error.. In file included from In instantiation of 'struct UtlSharedIPCWrapper': ALBFDaemon.cpp:347:31: required from here UtlSharedIPCWrapper.h:49:10: error: 'long long unsigned int' is not a class, struct, or union type – johnco3 Feb 08 '16 at 15:04

1 Answers1

1

Why not just

// I don't know the correct signature here
void setSharedDataValue(const typename T::value_type& rSharedDataValue)      {
    boost::interprocess::scoped_lock<upgradable_mutex_type> lock(mMutex);
    mSharedData.insert(rSharedDataValue);
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • I tried the above with visual studio 2015, but I get : C2825: 'T': must be a class or namespace when followed by '::'. Not sure of the syntax is. Certainly the intent of providing a T::value_type is exactly what I would like to provide as I need to insert a std::pair element into a std::map in this case, I am not sure what would happen with this code in the case where I have a UtlSharedIPCWrapper - would this method disappear - this is a whole meta programming thing I am unclear about. – johnco3 Feb 08 '16 at 14:36
  • 1
    MSVC has some nonstandard behaviours related to name lookup in templates. Can you provide a /selfcontained/ example that reproduces your issue? – sehe Feb 08 '16 at 14:38