2017-09-11 1 views
0

このシナリオを試しています。構造体をmmappedファイルのベクトルにし、mmappedファイルから読み込む構造体(複数のインスタンス)を記述してください。構造体のベクトルがmmapになっている構造体

以下のコードでは、 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

各プロセスには独自の仮想メモリがあります。 1つのプロセスが別のプロセスのメモリにアクセスすることはできません(一部のプラットフォーム固有の方法を除きますが、これらの場合は動的メモリには適用されません)。

std::vectorは、デフォルトでstd::allocatorを使用して内部配列を割り当てます。 std::allocatorはダイナミックメモリを割り当てます。ベクトルをファイルに書き込むとき、そのベクトルはベクトルを書き込むプロセスの動的メモリを参照します。そのベクトルを別のプロセスで読み取ろうとすると、そのプロセスは元のプロセスが持っていた仮想メモリの場所に(純粋なチャンスでない限り)動的メモリを割り当てませんでした。したがって、そのようなベクトルを使用すると、未定義の動作が発生します

状態がダイナミックメモリに格納されているオブジェクトは、プロセス間で共有できません。


プロセス間で配列を共有するには、ベクトルではなくフラットな配列が必要です。

ただし、クラスのメンバーである配列のサイズは実行時に決定できないことに注意してください。したがって、そのサイズを動的にする必要がある場合は、非メンバとして配列を作成する必要があります。


さらに、ライン

map[x] = c; 

にあなたが実際にまだCoordオブジェクトを作成していないmap[x]に割り当てるコピーします。 Coordは簡単にコピーできないため、これは未定義の動作です。ライターのコードでさえもクラッシュしなかったのは純粋に不運でした。

関連する問題