具有映射的结构向量的结构
Struct having vector of structs mmapped
我正在尝试这种情况 - 编写一个结构(多个实例),它有一个结构向量到映射文件并从映射文件中读取。
在下面的代码中;当从同一个程序执行上下文调用 readFromMemMap() 时,读取似乎是成功的。但是如果我将 readFromMemMap() 移动到另一个 cpp 文件并且 运行;然后发生段错误。
感谢 pointers/inputs 解决此问题。
代码
#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
readFromMemMap() 在另一个 cpp 文件中
$ ./readFromMemMap
Reading from mmap
FileSize = 240
Size of struct Coords =24
Reading from mmap : 1 Coords vector size = 4
Segmentation fault
每个进程都有自己的虚拟内存。一个进程不能访问另一个进程的内存(除了某些特定于平台的方式,但这些情况不适用于动态内存)。
std::vector
默认使用 std::allocator
分配其内部数组。 std::allocator
分配动态内存。当您将向量写入文件时,该向量将引用写入该向量的进程的动态内存。如果您尝试在另一个进程中读取该向量,则该进程没有在原始进程所在的虚拟内存位置分配任何动态内存(除非纯属偶然)。因此,使用此类向量具有未定义的行为。
状态存储在动态内存中的对象不能在进程之间共享。
要在进程之间共享数组,您需要使用平面数组而不是向量。
但是,请记住,作为 class 成员的数组的大小无法在 运行 时确定。因此,如果您需要该大小是动态的,则需要将数组创建为非成员。
此外,在线
map[x] = c;
您将 assign 复制到 map[x]
,但实际上您还没有创建 Coord
对象。这具有未定义的行为,因为 Coord
不可简单复制。连writer代码都没有崩溃,纯属倒霉。
我正在尝试这种情况 - 编写一个结构(多个实例),它有一个结构向量到映射文件并从映射文件中读取。
在下面的代码中;当从同一个程序执行上下文调用 readFromMemMap() 时,读取似乎是成功的。但是如果我将 readFromMemMap() 移动到另一个 cpp 文件并且 运行;然后发生段错误。
感谢 pointers/inputs 解决此问题。
代码
#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
readFromMemMap() 在另一个 cpp 文件中
$ ./readFromMemMap
Reading from mmap
FileSize = 240
Size of struct Coords =24
Reading from mmap : 1 Coords vector size = 4
Segmentation fault
每个进程都有自己的虚拟内存。一个进程不能访问另一个进程的内存(除了某些特定于平台的方式,但这些情况不适用于动态内存)。
std::vector
默认使用 std::allocator
分配其内部数组。 std::allocator
分配动态内存。当您将向量写入文件时,该向量将引用写入该向量的进程的动态内存。如果您尝试在另一个进程中读取该向量,则该进程没有在原始进程所在的虚拟内存位置分配任何动态内存(除非纯属偶然)。因此,使用此类向量具有未定义的行为。
状态存储在动态内存中的对象不能在进程之间共享。
要在进程之间共享数组,您需要使用平面数组而不是向量。
但是,请记住,作为 class 成员的数组的大小无法在 运行 时确定。因此,如果您需要该大小是动态的,则需要将数组创建为非成员。
此外,在线
map[x] = c;
您将 assign 复制到 map[x]
,但实际上您还没有创建 Coord
对象。这具有未定义的行为,因为 Coord
不可简单复制。连writer代码都没有崩溃,纯属倒霉。