#c #segmentation-fault #shared-memory
#c #ошибка сегментации #разделяемая память #c
Вопрос:
Я сделал проект в Netbeans, и он там отлично работает. Но когда я пытаюсь скомпилировать с помощью makefile, я получаю ошибку сегментации. Почему я не могу получить доступ к общей памяти? Должен ли я использовать 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 $@
Ответ №1:
Вы не можете преобразовать возвращаемый тип mmap в std::string . std::string является типом c , отличным от POD. Вам нужно будет вызвать конструктор std::string, который затем, вероятно, выполнит динамическое распределение (однако для этого может потребоваться небольшая оптимизация строк). Это приведет к тому, что строка фактически не будет находиться в разделяемой памяти, за исключением, возможно, поля размера в зависимости от того, как оно реализовано.
Если вы хотите сохранить строковый буфер в общей памяти, вам следует просто использовать символ * или посмотреть на библиотеки, такие как Boost .Межпроцесс. Библиотека является кроссплатформенной и значительно упростит размещение всех типов типов в разделяемой памяти, конечно, за счет использования Boost.
Ответ №2:
Первое правило таких проблем: всегда проверяйте возвращаемое значение системных вызовов. Второе правило таких проблем: запускайте в отладчике и учитесь использовать посмертный анализ.
В вашем конкретном случае произошел сбой mmap, но вы не смогли проверить его код возврата, что означает, что вы пытались разыменовать указатель -1
.
Я не уверен точно, почему произошел сбой mmap, но когда я действительно создаю example.txt
, он перестает работать на моей машине. Мне кажется, что вам также не удалось проверить код возврата из кода, подготавливающего буфер для сопоставления.
Наконец, std::string работает не так, как вы думаете. Выделение памяти для нее с помощью mmap просто не будет правильным. std::string выделяет свою собственную память, и если вы хотите, чтобы она размещалась в явно распределенном пространстве, вам нужно посмотреть, предоставив ему пользовательский распределитель.
Отредактировано для добавления
Если вы настаиваете на выделении вашего std::string
в mmap (в отличие от данных, которые должна содержать строка), тогда размер, который вы отправляете в mmap, должен sizeof(std::string)
, а не string.length
. Это все равно не было бы семантически корректным, так как вы бы вызывали std::string.operator=
без предварительного создания объекта. Поэтому рабочая программа будет:
std::string *func(const std::string amp;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 (вам нужно будет включить <new>
). Опять же, это, вероятно, не то, что вы хотите, поскольку std::string
оно будет находиться в вашей mmaped памяти, но эта фактическая строка, скорее всего, нет.
Ответ №3:
Используйте размещение new для создания std::string в местоположении shmem
new (shmem) std::string(content)
Но это, вероятно, все равно не будет работать для межпроцессного взаимодействия только из-за
- макет std::string может отличаться из-за параметров компилятора (или типа компилятора)
- внутренние поля std::string ссылаются на другую память, локальную для вашего процесса, как уже указал grepsedawk