2017-09-11 17 views
0

이 시나리오를 시도하고 있습니다. 구조체 벡터가 mmapped 파일이고 mmapped 파일에서 구조체가있는 구조체 (여러 인스턴스)를 작성합니다.구조체 벡터가 구조체로 된 구조체

아래 코드에서; 동일한 프로그램 실행 컨텍스트에서 readFromMemMap()이 호출되면 읽기가 성공한 것 같습니다. 하지만 내가 다른 cpp 파일로 readFromMemMap()을 옮겨서 실행하면; 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 

출력 다른 CPP 파일에

$ ./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()

$ ./readFromMemMap 
    Reading from mmap 

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

std :: vector를 파일에 쓸 수 없습니다. 배열 인덱스는 0에서 시작합니다. –

답변

1

각 프로세스에는 고유 한 가상 메모리가 있습니다. 하나의 프로세스는 다른 프로세스의 메모리에 액세스 할 수 없습니다 (일부 플랫폼의 특정 방법을 제외하고 이러한 경우는 동적 메모리에 적용되지 않습니다).

std::vector은 기본적으로 std::allocator을 사용하여 내부 배열을 할당합니다. std::allocator은 동적 메모리를 할당합니다. 벡터를 파일에 쓸 때 벡터는 벡터를 쓰는 프로세스의 동적 메모리를 나타냅니다. 다른 프로세스에서 해당 벡터를 읽으려고하면 해당 프로세스는 원래 프로세스가 있던 가상 메모리 위치에 동적 메모리를 할당하지 않습니다 (순수한 기회가 아니면). 따라서 그러한 벡터를 사용하면 정의되지 않은 동작이 발생합니다.

상태가 동적 메모리에 저장된 개체는 프로세스간에 공유 할 수 없습니다.


프로세스간에 배열을 공유하려면 벡터가 아닌 평면 배열이 필요합니다.

그러나 클래스의 멤버 인 배열의 크기는 런타임에 결정할 수 없습니다. 따라서 동적 인 크기가 필요한 경우 배열을 비회원으로 만들어야합니다.


또한, 라인

map[x] = c; 

에 당신은 당신이 실제로 아직 Coord 오브젝트를 작성하지 않은 map[x]에 할당 복사합니다. Coord은 쉽게 복사 할 수 없기 때문에이 동작은 정의되지 않았습니다. 작가 코드가 충돌하지 않는 것은 완전히 불행이었습니다.