segfault при использовании mmap - PullRequest
2 голосов
/ 03 октября 2011

Я пытаюсь использовать mmap впервые для хранения объекта дерева с большим количеством данных. Класс дерева в основном содержит указатель на корень класса Node, и каждый экземпляр Node имеет массив указателей на своих потомков. Я думаю, что mmap делает то, что должен, потому что я могу получить доступ к постоянным членам дерева, но когда я пытаюсь получить доступ к указателю на корень, я получаю ошибку segfault.

Вот как создать дерево с корневым узлом:

int main(int argc, char *argv[])
{
    Tree *map;
    ...
    map = (Tree*)mmap(0, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (map == MAP_FAILED) {
        close(fd);
        perror("Error mmapping the file");
        exit(EXIT_FAILURE);
    }


    Node* root = new Node("data");
    map->set_root(root);
        ...
}

Вот как я могу получить доступ к Дереву:

int main(int argc, char *argv[])
{
    int i;
    int fd;
    Tree *map;

    fd = open(FILEPATH, O_RDONLY);
    if (fd == -1) {
        perror("Error opening file for reading");
        exit(EXIT_FAILURE);
    }

    map = (Tree*)mmap(0, FILESIZE, PROT_READ, MAP_SHARED, fd, 0);

    if (map == MAP_FAILED) {
       close(fd);
       perror("Error mmapping the file");
       exit(EXIT_FAILURE);
    }

    Node* root = map->root();
    cout << root->data();
    ...

Вывод root-> data () обеспечивает ошибку по умолчанию. Кто-нибудь может дать мне подсказку, где я не прав? Пожалуйста, скажите, если я не проясню свою проблему.

Заранее спасибо.

Мадс

Ответы [ 3 ]

5 голосов
/ 03 октября 2011

Это беспорядок.Вам нужно понять, как new и delete работают, прежде чем пытаться делать то, что вы пытаетесь сделать.

С чего начать.

  1. map = (Tree*)mmap(0, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); Это просто говорит, относитесь к этомубит памяти, как будто это Tree, вы не создали дерево в этом бите памяти.
  2. Когда вы вызываете new, он выделяет объект Node где-то в памяти ивы удерживаете указатель на это в своем дереве, когда оно повторно открывается в другом месте, указатель больше не действителен.

Вам также нужно хранить все узлы в вашем отображенном блоке ... ТамЭто не очень простой ответ на этот вопрос, за исключением попыток понять собственные распределители памяти.

0 голосов
/ 03 октября 2011

Когда вы звоните mmap(), вы просто получаете блок сырой памяти.Таким образом, вы не можете наивно разыменовывать указатель map, не вызывая некоторый тип неопределенного поведения ... просто приведение памяти, возвращенной из mmap(), к типу Tree*, как вы это сделали, на самом деле не создает объект Treeв отображенной памяти.

Если вы хотите сконструировать или даже скопировать сконструировать объект Tree в памяти, возвращенной из mmap, вы можете захотеть использовать placement new.Например, вы можете сделать что-то вроде следующего:

void* map;
map = mmap(0, FILESIZE, PROT_READ, MAP_SHARED, fd, 0);

//...error checking

Tree* tree = new(map) Tree(); //placement new syntax

Это фактически создаст объект по умолчанию Tree в памяти, возвращенной из mmap, и в этот момент вы можете правильно использоватьtree переменная-указатель для дальнейшего добавления узлов в дерево.Например, следующий код теперь может быть вызван без создания неопределенного поведения:

Node* root = new Node("data");
tree->set_root(root);

При placement new переменная tree указывает на фактический объект Tree, и теперь вы можетедолжным образом разыменуйте этот указатель, а также любые методы, связанные с этим объектом.

Однако следует помнить, что при использовании placement new вам придется вручную вызывать деструктор для вашего Treeобъект, и вам придется вручную освободить память, выделенную через mmap() ... вы не можете вызвать delete на Tree*.

0 голосов
/ 03 октября 2011

Это не сработает. Если root() - это виртуальный метод, вы находитесь внутри, так как указатели vtable указывают на методы в текущем процессе. может работать, если вы не вызываете виртуальные методы, но, вероятно, поведение не определено.

Вероятно, лучше обмениваться данными между процессами, а не объектами. Позвольте объектам иметь дескриптор к данным, и защитить пользователя объекта от деталей декодирования данных. Node* root = new Tree(memory_mapped_memory);

...