views:

145

answers:

1

I'm pulling my hair due to the following problem: I am following the example given in boost.interprocess documentation to instantiate a fixed-size ring buffer buffer class that I wrote in shared memory. The skeleton constructor for my class is:

template<typename ItemType, class Allocator >
SharedMemoryBuffer<ItemType, Allocator>::SharedMemoryBuffer( unsigned long capacity ){

    m_capacity = capacity;

    // Create the buffer nodes.
    m_start_ptr = this->allocator->allocate();  // allocate first buffer node
    BufferNode* ptr = m_start_ptr;
    for( int i = 0 ; i < this->capacity()-1; i++ ) {
        BufferNode* p = this->allocator->allocate();    // allocate a buffer node
    }
}

My first question: Does this sort of allocation guarantee that the buffer nodes are allocated in contiguous memory locations, i.e. when I try to access the n'th node from address m_start_ptr + n*sizeof(BufferNode) in my Read() method would it work? If not, what's a better way to keep the nodes, creating a linked list?

My test harness is the following:

// Define an STL compatible allocator of ints that allocates from the managed_shared_memory.
// This allocator will allow placing containers in the segment
typedef allocator<int, managed_shared_memory::segment_manager>  ShmemAllocator;

//Alias a vector that uses the previous STL-like allocator so that allocates
//its values from the segment
typedef SharedMemoryBuffer<int, ShmemAllocator> MyBuf;

int main(int argc, char *argv[]) 
{
    shared_memory_object::remove("MySharedMemory");

    //Create a new segment with given name and size
    managed_shared_memory segment(create_only, "MySharedMemory", 65536);

    //Initialize shared memory STL-compatible allocator
    const ShmemAllocator alloc_inst (segment.get_segment_manager());

    //Construct a buffer named "MyBuffer" in shared memory with argument alloc_inst
    MyBuf *pBuf = segment.construct<MyBuf>("MyBuffer")(100, alloc_inst);
}

This gives me all kinds of compilation errors related to templates for the last statement. What am I doing wrong? Is segment.construct<MyBuf>("MyBuffer")(100, alloc_inst) the right way to provide the two template parameters?

+1  A: 

My first question: Does this sort of allocation guarantee that the buffer nodes are allocated in contiguous memory locations, i.e. when I try to access the n'th node from address m_start_ptr + n*sizeof(BufferNode) in my Read() method would it work?

No. The reason being that you have the first node only. All BufferNode objects that you create are not being saved (say, in a linked-list fashion) and contribute to memory leaks. Further, this style of allocation does not gurantee contiguous memory locations. Random access (as you state later in your question) will most likely fail. To get contiguous memory, you need to create an array (perhaps dynamic) of BufferNode objects.

This gives me all kinds of compilation errors related to templates for the last statement. What am I doing wrong?

Difficult to say without knowing about the actual errors. Further, do you understand your code (and how Boost::Interprocess fits in or how the allocator works)?

Note that the example you cite creates a vector which is guaranteed to have contiguous memory for its contained objects. The only difference here is that the objects are created on a shared memory segment rather than the free store which is what typically happens when you don't specify an allocator as the second parameter and the default one is used.

dirkgently
Thanks for the reply. How can I create an array of BufferNode objects using the provided allocator? I must admit I'm a little shaky on boost.interprocess and the examples are sparse.
recipriversexclusion
Or, would it be better to create a vector to store the BufferNodes within the buffer?
recipriversexclusion
I'd say use a `deque<BufferNode>` (or at least a `vector<BufferNode>`) and have the `SharedMemoryBuffer` hide this implementation detail. The final choice of a container depends on your needs.
dirkgently