2017-09-11 8 views
0

J'essaie ce scénario - écrire une structure (plusieurs instances) qui a un vecteur de struct dans le fichier mmapped et lire à partir du fichier mmapped.Struct ayant vecteur de structures mmapped

Dans le code ci-dessous; Lorsque readFromMemMap() est appelée à partir du même contexte d'exécution de programme, la lecture semble réussie. Mais si je déplace readFromMemMap() dans un fichier cpp différent et que je cours; alors une erreur de seg se produit.

Merci pour tous les pointeurs/entrées pour résoudre ce problème.

code

#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; 
} 

Compile

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

sortie

$ ./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() dans un autre fichier cpp

$ ./readFromMemMap 
    Reading from mmap 

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

Vous ne pouvez pas écrire un fichier std :: vector dans un fichier. Les index de tableau commencent à 0. –

Répondre

1

Chaque processus a sa propre mémoire virtuelle. Un processus ne peut pas accéder à la mémoire d'un autre processus (sauf de certaines manières spécifiques à une plate-forme, mais ces cas ne s'appliquent pas à la mémoire dynamique).

std::vector alloue sa matrice interne en utilisant std::allocator par défaut. std::allocator alloue de la mémoire dynamique. Lorsque vous écrivez un vecteur dans un fichier, ce vecteur fait référence à la mémoire dynamique du processus qui écrit le vecteur. Si vous essayez de lire ce vecteur dans un autre processus, ce processus n'a pas alloué de mémoire dynamique dans l'emplacement de mémoire virtuelle où se trouvait le processus d'origine (sauf par hasard). Par conséquent, l'utilisation d'un tel vecteur a un comportement indéfini.

Les objets dont l'état est stocké dans la mémoire dynamique ne peuvent pas être partagés entre les processus. Pour partager un tableau entre les processus, vous avez besoin d'un tableau plat plutôt que d'un vecteur. Cependant, gardez à l'esprit que la taille d'un tableau membre d'une classe ne peut pas être déterminée au moment de l'exécution. Par conséquent, si vous souhaitez que cette taille soit dynamique, vous devez créer le tableau en tant que non-membre.


En outre, sur la ligne

map[x] = c; 

Vous copiez assigner à map[x] où vous ne l'avez pas fait encore créé un objet Coord. Ceci a un comportement indéfini puisque Coord n'est pas trivialement copiable. Il a été purement malchanceux que même le code de l'auteur ne plante pas.