我在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 $@
答案 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)
但由于
,这可能仍不适用于进程间通信