写入共享内存时出现分段错误

时间:2016-10-02 04:40:25

标签: c++ segmentation-fault shared-memory

我在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 $@

.cpp.o:
    $(CC) $(CFLAGS) $< -o $@

3 个答案:

答案 0 :(得分:3)

您无法将mmap的返回类型强制转换为std :: string。 std :: string是c ++非POD类型。您需要调用std :: string的构造函数,然后可能会执行动态分配(但是,它可以使用小的字符串优化)。这会导致字符串实际上不在共享内存中,除非它的大小字段取决于它的实现方式。

如果要在共享内存中存储字符串缓冲区,则应使用char *,或查看Boost.Interprocess之类的库。该库是跨平台的,它将使各种类型的共享内存更加简单,当然是以提升Boost为代价。

答案 1 :(得分:1)

此类问题的第一条规则:始终检查系统调用的返回值。 此类问题的第二条规则:在调试器中运行,并学习使用事后分析。

在您的特定情况下,mmap失败,但您无法检查其返回代码,这意味着您尝试取消引用指针-1

我不确定mmap为什么会失败,但是当我实际创建example.txt时,它会停止在我的机器上失败。在我看来,您也无法检查准备缓冲区以进行映射的代码中的返回代码。

最后,std :: string不能像你认为的那样工作。使用mmap为它分配内存根本就不会做正确的事情。 std :: string分配自己的内存,如果你希望它驻留在一个显式的mmaped空间,你需要查找给它一个自定义分配器。

已编辑添加

如果您坚持在mmap中分配std::string(而不是字符串应包含的数据),那么您发送到mmap的大小应为sizeof(std::string),而不是{{ 1}}。这仍然不是语义上正确的,因为在没有首先构造对象的情况下调用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; } 放入mmaped内存中。它使用placement new来初始化它(您需要包含std::string)。同样,这可能不是您想要的,因为<new>将驻留在您的mmaped内存中,但实际的字符串可能不会。

答案 2 :(得分:0)

使用placement new在shmem位置构建std :: string

new (shmem) std::string(content)

但由于

,这可能仍不适用于进程间通信
    由于编译器选项(或编译类型),
  • std :: string布局可能不同
  • std :: string内部字段引用其他内存,您的进程本地为grepsedawk已指向