Ion; thank you!!
I found the errors in my prior code thanks to your tip and used the improvements you suggested. I had unwittingly declared variables with very similar names and different types, leading to confused behavior. Anyway that is solved and I now have a working implementation of a mutex synchronised interprocess vector of strings. Have included it below in case it’s of use to anyone else trying the same…..
A further question if I may?
What is the best approach to extend a managed_shared_memory_segment? I can dynamically add (via write() function) shared vector elements until such time as an interprocess_exception boost_interprocess::bad_alloc is thrown; when the memory allocated to the shared segment is filled. Is there a way to handle this exception so that the segment can be extended with more memory and then resume adding data elements to the vector? Or perhaps some other way to detect the segment memory is running short and take action to extend it?
Thanks again,
Riskybiz.
Code:
Class Definition:
#ifndef SHARED_MEMORY_WRAPPER_H//if not defined already
#define SHARED_MEMORY_WRAPPER_H//then define it
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <iostream>
#include <stdexcept>
using namespace boost::interprocess;
class SharedMemoryWrapper
{
public:
SharedMemoryWrapper(const std::string &name, bool server) : m_name(name), m_server(server)
{
if (server)
{
//Clean up resources from any prior instances
named_mutex::remove("named_mutex");
shared_memory_object::remove(m_name.c_str());
//Create shared memory
m_segment = new managed_shared_memory(create_only, m_name.c_str(), 1000000);
//Create allocators
CharAllocator charallocator(m_segment->get_segment_manager());
StringAllocator stringallocator(m_segment->get_segment_manager());
//This vector is fully constructed in shared memory. All pointers
//buffers are constructed in the same shared memory segment
//This vector can be safely accessed from other processes.
sharedSegmentVector = m_segment->construct<MyShmStringVector>("sharedSegmentVector")(stringallocator);
}
else
{
try
{
//Open the shared segment
m_segment = new managed_shared_memory(open_only, name.c_str());
//Find the vector using the c-string name and open it
sharedSegmentVector = m_segment->find<MyShmStringVector>("sharedSegmentVector").first;
}
catch(interprocess_exception ipe)
{
std::cout << "Error: Interprocess Exception: " << ipe.what() << std::endl;
}
catch(...)
{
std::cout << "Error: Unknown Exception: " << std::endl;
}
}
m_mutex = new named_mutex(open_or_create, "named_mutex");
}
~SharedMemoryWrapper()
{
/*
//Destructor: Will remove the shared memory resources
if (m_server)
{
named_mutex::remove("named_mutex");
//Destroy the vector from the managed_shared_memory
//m_segment->destroy_ptr(sharedSegmentVector);//This will free all strings that the vector contains
m_segment->destroy<MyShmStringVector>("sharedSegmentVector");//Destroy the vector
//Is it necessary to destroy the allocators here?
//Remove the managed_shared_memory; this may fail if the memory does not exist or is mapped or opened by another process
shared_memory_object::remove(m_name.c_str());
} */
//Delete instance members
delete m_mutex;
delete m_segment;
}
//Writer
void write(const std::string &inStr)
{
try
{
CharAllocator charallocator(m_segment->get_segment_manager());
scoped_lock<named_mutex> lock(*m_mutex);
MyShmString shmStr(inStr.c_str(), charallocator);
sharedSegmentVector->push_back(shmStr);
}
catch(interprocess_exception ipe)
{
std::cout << "Error in SharedMemoryWrapper::write(): interprocess_exception: "<< ipe.what() << std::endl;
}
catch(...)
{
std::cout << "Error in SharedMemoryWrapper::write(): unknown error" << std::endl;
}
}
//Reader
std::string read(size_t &index)
{
try
{
scoped_lock<named_mutex> lock(*m_mutex);
const MyShmString &shmStr = (*sharedSegmentVector)[index];
std::string stdStr(shmStr.begin(), shmStr.end());
return stdStr;
}
catch(interprocess_exception ipe)
{
std::cout << "Error in SharedMemoryWrapper::read(): interprocess_exception: "<< ipe.what() << std::endl;
}
catch(std::range_error re)
{
std::cout << "Error in SharedMemoryWrapper::read(): range_error: " << re.what() << std::endl;
}
catch(...)
{
std::cout << "Error in SharedMemoryWrapper::read(): unknown error "<< std::endl;
}
return "Error in SharedMemoryWrapper::read()";
}
//Vector Size
size_t getSize() const
{
return this->sharedSegmentVector->size();
}
private:
//Typedefs
typedef boost::interprocess::allocator<char, managed_shared_memory::segment_manager> CharAllocator;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> MyShmString;
typedef boost::interprocess::allocator<MyShmString, managed_shared_memory::segment_manager> StringAllocator;
typedef boost::interprocess::vector<MyShmString, StringAllocator> MyShmStringVector;
bool m_server;
std::string m_name;
managed_shared_memory *m_segment;
MyShmStringVector *sharedSegmentVector;
named_mutex *m_mutex;
};//class
#endif//header guard
Test Programmes:
// PrepareSharedMemoryVectorOfStrings.cpp : Defines the entry point for the console application.
//
#include "SharedMemoryWrapper.h"
#include <iostream>
#include <string>
#include <sstream>
int main(int argc, char *argv[])
{
SharedMemoryWrapper *smw = new SharedMemoryWrapper("SharedMemoryTest", true);
size_t cnt(0);
while(cnt < 100)
{
//Convert number to string representation
std::string cntStr = static_cast<std::ostringstream*>( &(std::ostringstream() << cnt) )->str();
//Write to shared memory vector
smw->write("Iteration: " + cntStr);
cnt++;
}
size_t vecSize = smw->getSize();
std::cout << "Elements Present: "<< vecSize << std::endl;
delete smw;
return 0;
}
// AccessSharedMemoryVectorOfStrings.cpp : Defines the entry point for the console application.
//
#include "SharedMemoryWrapper.h"
#include <iostream>
#include <string>
int main(int argc, char *argv[])
{
SharedMemoryWrapper *smw = new SharedMemoryWrapper("SharedMemoryTest", false);
std::string outStr;
for(size_t index = 0; index < 100; index++)
{
outStr = smw->read(index);
std::cout << outStr << std::endl;
}
delete smw;
return 0;
}