views:

207

answers:

2

I have a problem with boost shared_memory_object and mapped_region. I want to write a set of objects (structures) in the memory object. If the structure contains just a char, everything is ok; if I just add an int to the structure, then if I put too many objects (let's say 70, so much less than the limit of the block) I get a segmentation fault when writing.

So far I have just seen examples where simple chars are written to the shared memory, but I have not read anything about the kind of objects that can be used. I am wondering if I have to make the conversion between my objects and a byte stream, or if such a function already exists. Or if I am just doing something wrong in my code. The commented lines are the ones that give me a segfault when decommented...

#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <iostream>
#include <unistd.h>

struct Record {
    char c;
    int i;
//  float f;
//  double d;
//  char cs[32];
//  boost::interprocess::string is;
//  std::vector<int> v;

    Record() {}
    Record(int _k) { Init(_k); }

    void Init(int _k = 0) {
        c = _k + 65;
        i = _k;
//      f = _k + _k/100.0;
//      d = _k + _k/1000.0;
//      is = "interprocess string";
//      for(int j = 0; j < _k; ++j) v.push_back(j);
    }
};

int main(int argc, char *argv[])
{
   using namespace boost::interprocess;
   using std::cerr;
   using std::endl;

   int nObjects = 0;
   size_t blockSize = 1024;

   static std::string sharedObjName("MySharedMemory");      // why static?

   const int writer = 1, reader = 2, error = -1;
   int operation = error;

   if(argc >= 2) {
      if(argv[1][0] == 'w') operation = writer;
      if(argv[1][0] == 'r') operation = reader;
   }
   if(argc == 1) operation = writer;

   if(operation == writer)      // Writer process
   {
      cerr << "Number of objects to write = ";
      std::cin >> nObjects;

      // Remove shared memory on construction and destruction
      struct shm_remove {
         shm_remove() { shared_memory_object::remove(sharedObjName.c_str()); }
         ~shm_remove(){ shared_memory_object::remove(sharedObjName.c_str()); }
      } remover;

      shared_memory_object shm(create_only, sharedObjName.c_str(), read_write);

      shm.truncate(blockSize);

      mapped_region region(shm, read_write);

      offset_t shmSize;
      shm.get_size(shmSize);

      // Produce and write data
      Record *pData0 = static_cast<Record*>(region.get_address());
      Record *pData  = pData0;

      for(int i = 0; i < nObjects; ++i) {
         if(pData0 + blockSize - pData < signed(sizeof(Record))) {
            cerr << "Error: memory block full!" << endl;
            break;
         }
         pData->Init(i);
         pData += sizeof(Record);
      }

      //Launch child process
      pid_t pId = fork();

      if(pId == 0)
      {
         std::string s(argv[0]); s += " r";

         if(std::system(s.c_str()) != 0) {
            cerr << "Error launching reader process." << endl;
            exit(1);
         }
         exit(0);
      }
      else if(pId > 0)
      {
         sleep(2);
         cerr << "Writer has finished!" << endl;
      }
      else  // pId < 0
         exit(-1);
   }
   else if(operation == reader)         // Reader process
   {
      shared_memory_object shm (open_only, sharedObjName.c_str(), read_only);

      mapped_region region(shm, read_only);

      Record *pData = static_cast<Record*>(region.get_address());

      for(int i = 0; i < nObjects; ++i)  {
         // Print pData...
         pData += sizeof(Record);
      }
   }
   else
      exit(1);

   return 0;
}

Thank you for any hint!

MacOS X 10.6.2 - gcc 4.2 - Boost 1.41.0

+1  A: 
pData += sizeof(Record);

That line is the problem. Pointer arithmetic means changes are in "units" of the underlying pointer type, in this case Record. So if you want to increment to the next record, you should do pData++, rather than pData += sizeof(Record), which will increase the pointer by 64 bytes (assuming sizeof(Record) is 8 - 8*8 = 64).

You've got a similar pointer arithmetic error in the size check:

pData0 + blockSize - pData < signed(sizeof(Record))

You probably want something like:

blockSize/sizeof(Record)-(pData-pData0) <= 0
BeeOnRope
You are right... things go much better now.Thank you!
Pietro
A: 

I still have a problem: if in the structure I add a boost::interprocess::string, I get a segmentation fault... Is it normal?
I knew I could not use std::string, but...

Pietro