2011-10-03 331 views
2

我想第一次使用mmap来存储一个树中有大量数据的对象。树类基本上包含一个指向类Node的根的指针,每个Node实例都有一个指向它的子元素的指针数组。我认为mmap正在做它应该做的事情,因为我可以访问树的常量成员,但是当我尝试访问指向根的指针时,我得到了段错误。使用mmap时的段错误

下面是如何创建树与根节点:

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(); 
    ... 

根 - >数据的输出()提供了一个段错误。任何人都可以给我一个暗示我错在哪里?请说,如果我没有明确表示我的问题。

在此先感谢。

Mads

+0

你的代码很混乱。你必须使用'main()'的版本,但它们是不同的 - 为什么在第一个版本中有一个'new',但不是在第二个版本中?无论如何,由于您只是在普通的免费商店中分配节点,而不是在映射的内存中分配节点,因此代码不太可能执行您的想法。 –

回答

4

这是一团糟。在尝试做什么之前,您需要了解newdelete的工作方式。

从哪里开始。

  1. map = (Tree*)mmap(0, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);这只是说,治疗的内存位,就好像它是一个Tree,你不是在内存位构建的树。
  2. 当你调用new时,它会分配一个Node对象,在内存中的某个地方,当你在其他地方重新打开指针时,它将持有一个指向树中的指针,指针不再有效。

您还需要将映射块中的所有节点都存储......除了尝试了解自定义内存分配器之外,没有真正简单的答案。

+0

好的...谢谢,我会看看它 – madshov

+0

一旦你开始在mmap的区域内分配你的节点,你还会发现使用指针是有问题的(因为文件不一定映射到每个进程中的地址相同)。您可以将地图视为一个节点数组,然后存储索引而不是指针。 – Useless

0

这是行不通的。如果root()是一种虚拟方法,则虚拟方法会因为vtable指针指向当前进程中的方法而被调整。它可能工作,如果你不调用任何虚拟方法,但它可能是未定义的行为。

在进程之间共享数据可能更好,而不是对象。让对象处理数据,并将对象的用户与解码数据的细节隔离开来。 Node* root = new Tree(memory_mapped_memory);

0

当你调用mmap()时,你基本上只是获得一块原始内存。因此,您不能天真地取消引用map而不调用某种类型的未定义行为...只需将从mmap()返回的内存转换为类型Tree*就像您所做的那样,实际上并未在映射的内存中构造Tree对象。

如果您希望在mmap返回的内存中构造或者甚至复制构造Tree对象,那么您可能需要使用placement new进行研究。举例来说,你可以做类似如下:

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

//...error checking 

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

mmap返回的内存实际上将默认构造一个Tree对象,在这一点上,可以适当使用tree指针变量,以进一步将节点添加到树中。例如,下面的代码现在可能不会产生未定义行为调用:

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

随着placement new,实际Tree对象被指向的变量tree,你现在可以正确地解引用该指针,以及任何与该对象关联的方法。要牢记

一个主要项目是,虽然使用placement new时,你必须手动调用析构函数为您Tree对象,你将不得不手动释放,你已经通过mmap()分配的内存...您不能在Tree*上致电delete