2011-10-03 4 views
2

많은 양의 트리 객체를 저장하기 위해 mmap을 처음 사용하려고합니다. tree 클래스는 기본적으로 Node 클래스의 루트에 대한 포인터를 포함하고 있으며 각 Node 인스턴스에는 자식 노드에 대한 포인터 배열이 있습니다. 나는 나무의 상수 멤버에 액세스 할 수 있기 때문에 mmap이하는 일을하고 있다고 생각하지만 루트에 대한 포인터에 액세스하려고하면 segfault가 생깁니다.mmap을 사용할 때 segfault

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

이 루트 레벨> 데이터의 출력은() 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); 
     ... 
} 

내가 액세스하는 방법 트리입니다 : 여기

는 루트 노드와 트리를 생성하는 방법이다 . 아무도 내가 틀린 곳으로 나에게 힌트를 줄 수 있습니까? 제 문제를 분명히하지 않는다고 말하십시오.

미리 감사드립니다.

Mads

+0

코드가 혼란 스럽습니다. 당신은'main()'의 버전을 가져야 만합니다. 그러나 그것들은 다릅니다. 왜 첫 번째 버전에는'new'가 있지만 두 번째 버전에는'new'가 있습니까? 어쨌든, 당신이 코드를 생각할 수있는 일은 거의 없을 것입니다. 단지 노드를 할당 된 메모리가 아니라 일반 자유 저장소에 할당하기 만하면됩니다. –

답변

4

이것은 엉망입니다. 할 일을 시도하기 전에 newdelete이 어떻게 작동하는지 이해해야합니다.

시작하기.

  1. map = (Tree*)mmap(0, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);이 단지 당신이 메모리의 비트에 나무를 구축 적이 없다하는 Tree 인 것처럼 메모리의 비트 치료를 말한다.
  2. new을 호출하면 메모리에 어딘가에 Node 개체가 할당되고 트리에 포인터가있는 상태에서 다른 곳으로 다시 열리면 포인터가 더 이상 유효하지 않습니다.

매핑 된 블록에 모든 노드를 저장해야합니다. 사용자 지정 메모리 할당자를 이해하려고 시도하는 것을 제외하면 실제로는 쉽게 대답 할 수 없습니다.

+0

ok ... 덕분에 – madshov

+0

을 살펴 보겠습니다. mmap 영역에 노드를 할당하기 시작하면 포인터를 사용하는 것이 문제가 될 수 있습니다 (파일이 반드시 각 프로세스에서 동일한 주소). 지도를 노드의 배열로 취급하고 포인터 대신 포인터를 저장할 수 있습니다. – Useless

0

이것은 작동하지 않습니다. root()이 가상 메소드 인 경우 vtable 포인터가 현재 프로세스의 메소드를 가리 키므로 사용자가 호스를 사용합니다. 가상 메소드를 호출하지 않으면 일 수 있지만 아마 정의되지 않은 동작 일 것입니다.

개체가 아닌 프로세스간에 데이터를 공유하는 것이 좋습니다. 객체가 데이터에 대한 핸들을 갖도록하고 데이터의 디코딩 세부 사항에서 객체의 사용자를 보호합니다. Node* root = new Tree(memory_mapped_memory);

0

mmap()으로 전화하면 기본적으로 원시 메모리 블록이 생깁니다. 따라서 포인터 map을 참조하지 않고 정의되지 않은 동작을 호출하지 않아도됩니다. 마치 mmap()에서 반환 된 메모리를 Tree*으로 캐스팅하면 실제로 매핑 된 메모리에 Tree 개체가 생성되지 않습니다.

메모리에 Tree 개체가 mmap에서 반환되도록 구성하거나 복사하려는 경우 placement new을 사용하는 것이 좋습니다.예를 들어, 당신은 같은 일을 할 수있는 다음 : 실제로 mmap에서 반환 된 메모리에 Tree 객체를 기본-구성되며, 그 시점에서, 제대로하기 위해 tree 포인터 변수를 사용할 수 있습니다

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

//...error checking 

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

트리에 노드를 더 추가하십시오. 예를 들어, 다음 코드는 이제 정의되지 않은 동작 만들지 않고 호출 할 수 있습니다 : placement new

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

, 실제 Tree 객체가 변수 tree에 의해 지시되고, 그리고 당신이 이제 제대로 그 포인터뿐만 아니라 역 참조 해당 객체와 관련된 모든 메소드. 명심해야 할

하나 개의 주요 항목은하지만 placement new를 사용하는 경우, 수동으로 Tree 개체에 대한 소멸자를 호출해야합니다, 당신은 수동으로 mmap()를 통해 할당 한 메모리를 해제해야 할 것입니다 ... Tree*에서 delete으로 전화 할 수 없습니다.