具有mmapped结构的矢量的结构

时间:2017-09-11 08:45:49

标签: c++ linux struct stdvector mmap

我正在尝试这种情况 - 编写一个struct(多个实例),它有一个struct to mmapped文件的向量,并从mmapped文件中读取。

在下面的代码中;当从同一程序执行上下文调用readFromMemMap()时,读取似乎是成功的。但是如果我将readFromMemMap()移动到另一个cpp文件并运行;然后出现seg故障错误。

感谢您解决此问题的任何指针/输入。

代码

#include <iostream>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <vector>

#define FILEPATH "/tmp/mmapped.bin"
#define NUMINTS  (10)

struct _3DVec
{
  int x;
  int y;
  int z;
};

struct Coords
{
  std::vector<_3DVec> coords;
};

void readFromMemMap()
{
  std::cout << "\n----------------------------------\n" << std::endl;

  int fileSize = NUMINTS * sizeof(Coords);
  std::cout << "Reading from mmapped file\n" << std::endl;

  std::cout << "FileSize = " << fileSize << "\n\tSize of struct Coords =" << sizeof(Coords) << std::endl;

  int i;
  int fd;
  Coords *map;

  fd = open(FILEPATH, O_RDONLY);
  if (fd == -1) 
  {
    std::cerr << "Error opening file for reading" << std::endl;
    exit(EXIT_FAILURE);
  }

  map = (Coords*)mmap(0, fileSize, PROT_READ, MAP_SHARED, fd, 0);

  if (map == MAP_FAILED) 
  {
   close(fd);
   std::cerr << "Error mmapping the file" << std::endl;
   exit(EXIT_FAILURE);
  }

  /* Read the file from the mmap  */
  for (i = 1; i <=3; ++i) 
  {
    std::cout << "Reading from mmap : " << i << " Coords vector size = "  << map[i].coords.size() << std::endl;

    for (_3DVec v : map[i].coords)
    {
      std::cout << " x=" <<  v.x << ", y=" <<  v.y << ", z=" << v.z << std::endl;
    }
  }

  if (munmap(map, fileSize) == -1) 
  {
    std::cerr << "Error un-mmapping the file" << std::endl;
  }
  close(fd);
 }

int main(int argc, char *argv[])
{
  int fileSize = NUMINTS * sizeof(Coords);

  std::cout << "Writing to mmapped file " << std::endl;
  std::cout << "For writing, fileSize = " << fileSize << " \n\tSize of struct Coords =" << sizeof(Coords) << std::endl;

  int i;
  int fd;
  int result;

  Coords *map;  /* mmapped array of Coords's */

  fd = open(FILEPATH, O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600);
  if (fd == -1) 
  {
    std::cerr << "Error opening file for writing" << std::endl;
    exit(EXIT_FAILURE);
  }

  /* Stretch the file size to the size of the (mmapped) array of ints*/
  result = lseek(fd, fileSize-1, SEEK_SET);
  if (result == -1) 
  {
    close(fd);
    std::cerr << "Error calling lseek() to 'stretch' the file" << std::endl;
    exit(EXIT_FAILURE);
  }

  result = write(fd, "", 1);
  if (result != 1) 
  {
    close(fd);
    std::cerr << "Error writing last byte of the file" << std::endl;
    exit(EXIT_FAILURE);
  }

  /* Now the file is ready to be mmapped.*/
  map = (Coords*)mmap(0, fileSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  if (map == MAP_FAILED) 
  {
    close(fd);
    std::cerr << "Error mmapping the file" << std::endl;
    exit(EXIT_FAILURE);
  }

  /* Now write to mmapped file*/

 for (int x=1; x<=3; ++x)
 {
   Coords c;

   for (i = 1; i <=4; ++i)
  {
     _3DVec v;

     v.x = i;
     v.y = i*2;
     v.z = i*3;      

     c.coords.push_back(v);
    }
    map[x] = c; 
  }

  /* Don't forget to free the mmapped memory */
  if (munmap(map, fileSize) == -1) 
  {
    std::cerr << "Error un-mmapping the file" << std::endl; 
  }

  /* Un-mmaping doesn't close the file, so we still need to do that.*/
  close(fd);

  readFromMemMap();

  return 0;
}

编译

 g++ writeToMemMap.cpp -o writeToMemMap -std=c++11

输出

$ ./writeToMemMap
Writing to mmapped file 
For writing, fileSize = 240 
    Size of struct Coords =24

----------------------------------

Reading from mmapped file

FileSize = 240
    Size of struct Coords =24
Reading from mmap : 1 Coords vector size = 4
x=1, y=2, z=3
x=2, y=4, z=6
x=3, y=6, z=9
x=4, y=8, z=12
Reading from mmap : 2 Coords vector size = 4
x=1, y=2, z=3
x=2, y=4, z=6
x=3, y=6, z=9
x=4, y=8, z=12
Reading from mmap : 3 Coords vector size = 4
x=1, y=2, z=3
x=2, y=4, z=6
x=3, y=6, z=9
x=4, y=8, z=12
另一个cpp文件中的

readFromMemMap()

 $ ./readFromMemMap
   Reading from mmap

   FileSize = 240
       Size of struct Coords =24
   Reading from mmap : 1 Coords vector size = 4
   Segmentation fault

1 个答案:

答案 0 :(得分:1)

每个进程都有自己的虚拟内存。一个进程无法访问另一个进程的内存(除了某些特定于平台的方式,但这些情况不适用于动态内存)。

std::vector默认使用std::allocator分配其内部数组。 std::allocator分配动态内存。将向量写入文件时,该向量将引用写入向量的进程的动态内存。如果您尝试在另一个进程中读取该向量,则该进程尚未在原始进程所具有的虚拟内存位置中分配任何动态内存(除非纯粹的机会)。因此,使用此类向量具有未定义的行为。

状态存储在动态内存中的对象无法在进程之间共享。

要在进程之间共享数组,您需要使用平面数组而不是向量。

但是,请记住,在运行时无法确定作为类成员的数组的大小。因此,如果您需要该大小是动态的,则需要将该数组创建为非成员。

此外,在线

map[x] = c;

您可以将分配复制到尚未创建map[x]对象的Coord。这具有未定义的行为,因为Coord不是可轻易复制的。即使是编写器代码也没有崩溃,这纯粹是运气不好。