1

I'd like to keep a large number of (frequently duplicated) strings in shared-memory, so I'm using Boost's flyweight and interprocess basic_string functionality. To ensure that the string is actually stored in the shared-memory, I need to supply a custom allocator in the hashed_factory used by the flyweight.

However, that fails to compile (g++ 4.2.1) when I specify my custom allocator to hashed_factory... probably because it requires an extra argument to specify the segment manager. What's the syntax to get this working, or is there a better way to do this?

#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/flyweight.hpp>
#include <boost/flyweight/no_tracking.hpp>
#include <boost/flyweight/hashed_factory.hpp>

using namespace boost::flyweights;
using namespace boost::container;
using namespace boost::interprocess;


typedef boost::interprocess::allocator<boost::mpl::_1, boost::interprocess::managed_mapped_file::segment_manager> ShmFactoryEntryAllocator;

typedef boost::interprocess::allocator<char, boost::interprocess::managed_mapped_file::segment_manager> ShmAllocatorChar;

typedef boost::interprocess::basic_string<char, std::char_traits<char>, ShmAllocatorChar> ShmString;

// TODO: using ShmFactoryEntryAllocator does not work
typedef boost::flyweights::hashed_factory<boost::hash<ShmString>, std::equal_to<ShmString>, ShmFactoryEntryAllocator> ShmStringHashedFactory;
//typedef boost::flyweights::hashed_factory<boost::hash<ShmString>, std::equal_to<ShmString>, std::allocator<boost::mpl::_1> > ShmStringHashedFactory;

// TODO: need to be able to use a hashed_factory with our custom allocator.
typedef boost::flyweights::flyweight<ShmString, ShmStringHashedFactory> ShmFlyweightString;
//typedef boost::flyweights::flyweight<ShmString> ShmFlyweightString;


int main(int argc, char** argv)
{
    managed_mapped_file *segment = new managed_mapped_file(create_only, "memory.dat", 409600);
    ShmFactoryEntryAllocator factoryEntryAllocator(segment->get_segment_manager());

    // create a normal string in shared-memory.
    ShmString *ps1 = segment->construct<ShmString>("s1")("some shm normal string", factoryEntryAllocator);

    // create a flyweight string in shared memory.
    ShmFlyweightString *ps2 = segment->construct<ShmFlyweightString>(anonymous_instance)("some shm flyweight string", factoryEntryAllocator);

    return 0;
}

The lines after the TODO comments are the problematic lines, with the commented versions being the ones that work but do not use the correct allocator.

bovine
  • 5,303
  • 2
  • 18
  • 17

1 Answers1

0

It looks like you're right about the problem being the required constructor argument. The hashed_factory docs say:

The internal hashed container upon which hashed_factory_class is based is constructed with default initialized objects of type Hash, Pred and Allocator.

I wonder if you can work around this by making a subclass of the shared memory allocator that has a default constructor, passing the segment manager to the base class constructor. For example, something like this:

class MyShmAllocator : public ShmFactoryEntryAllocator {
public:
  static boost::interprocess::managed_mapped_file::segment_manager *segmentManager;

  MyShmAllocator()
  : ShmFactoryEntryAllocator(*segmentManager) {
  }
};

You would need to assign a "current" MyShmAllocator::segmentManager before any call to the constructor. It's a little ugly but I think it should work.

rhashimoto
  • 15,650
  • 2
  • 52
  • 80
  • I think that's getting closer, but I still can't quite get that to compile. As it turns out, the MyShmAllocator constructor should actually not dereference the pointer. But still, after switching the ShmStringHashedFactory to use MyShmAllocator it's still not quite happy... https://gist.github.com/bovine/5863647 – bovine Jun 26 '13 at 00:09
  • As it turns out, your answer is on the right track, but there is still more needed for a complete solution such as having a holder class that knows how to store in shared-memory and the locking policy. My colleague asked this same question on the Boost mailing list and got a very comprehensive answer from Joaquín M López Muñoz: http://permalink.gmane.org/gmane.comp.lib.boost.devel/242512 – bovine Jun 26 '13 at 04:49