2016-10-02 71 views
0

我在Netbeans中做了一個項目,它在那裏工作的很好。但是當我試圖使用makefile進行編譯時,我收到了Segmentation fault。爲什麼我無法訪問共享內存?我應該使用char *嗎?在共享內存中寫入時出現分段錯誤

#include <fstream> 
#include <string> 
#include <stdlib.h> 
#include <sys/mman.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <unistd.h> 

static std::string *shmem; //shared memory 

int main(int argc, char** argv) 
{  
    //open file and copy content 
    std::ifstream ifs("example.txt"); 
    std::string content((std::istreambuf_iterator<char>(ifs)), 
        (std::istreambuf_iterator<char>() )); 
    size_t size = content.size(); 

    //create shared memory page and copy content 
    shmem = static_cast<std::string*>(mmap(NULL, size, PROT_READ | PROT_WRITE, 
       MAP_SHARED | MAP_ANONYMOUS, -1, 0)); 
    *shmem = content; 

    return 0; 
} 

這裏是我的Makefile

CC  = g++ 
CFLAGS = -c -Wall -std=c++11 -pthread 
LDFLAGS = -pthread 
SOURCES = main.cpp 
OBJECTS =$(SOURCES:.cpp=.o) 
EXECUTABLE=MapReduce 

all: $(SOURCES) $(EXECUTABLE) 

$(EXECUTABLE): $(OBJECTS) 
    $(CC) $(LDFLAGS) $(OBJECTS) -o [email protected] 

.cpp.o: 
    $(CC) $(CFLAGS) $< -o [email protected] 

回答

3

你不能投MMAP的返回類型爲std :: string。 std :: string是一個C++非POD類型。你需要調用std :: string的構造函數,然後可能會執行動態分配(但是,它可以使用小字符串優化)。這將導致字符串實際上不在共享內存中,除非它的大小字段取決於它的實現方式。

如果你想在共享內存中存儲字符串緩衝區,你應該只使用一個char *,或者看看像Boost.Interprocess這樣的庫。該庫是跨平臺的,並且將使得將各種類型的內存放在共享內存中變得更加簡單,當然這是以增加Boost爲代價的。

1

這樣問題的首要規則:總是檢查系統調用的返回值。 這樣的問題的第二條規則:在調試器中運行,並學習使用事後分析。

在您的具體情況下,mmap失敗,但未能檢查其返回碼,這意味着您試圖取消引用-1的指針。

我不確定爲什麼mmap失敗,但當我實際創建example.txt時,它停止在我的機器上失敗。在我看來,你也沒有檢查準備映射緩衝區的代碼中的返回代碼。

最後,std :: string不會像你認爲的那樣工作。使用mmap爲它分配內存根本不會做正確的事情。 std :: string分配它自己的內存,如果你希望它駐留在一個明確的mmaped空間上,你需要查找給它一個自定義分配器。

編輯補充

如果你堅持在MMAP分配好自己的std::string(相對於該字符串應該包含數據),然後大小發送到MMAP應該sizeof(std::string),而不是string.length。這仍然不會在語義上正確,因爲您將在不首先構建對象的情況下調用std::string.operator=。一個工作程序會,爲此,有:

std::string *func(const std::string &str) 
{  
    //create shared memory page and copy content 
    void *memory = mmap(NULL, sizeof(std::string), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0); 
    if(memory==MAP_FAILED) { 
     throw std::bad_alloc(); 
    } 

    std::string *allocated_string = new(memory) std::string(); 
    *allocated_string = str; 

    return allocated_string; 
} 

這正確放置一個初始化std::string到mmaped內存。它使用新的位置來初始化它(您將需要包括<new>)。同樣,這可能不是您想要的,因爲std::string將駐留在您的mmaped內存中,但實際的字符串可能不會。

0

使用放置新構建的std ::在SHMEM位置

new (shmem) std::string(content) 

串但這可能仍不能用於進程間通信的工作只是因爲

  • 的std :: string佈局可能會有所不同由於編譯器選項(或種類的編譯器)
  • std :: string內部字段引用其他內存,您的進程本地作爲greurredawk已指出