Страницы

Поиск по вопросам

суббота, 13 июля 2019 г.

Использование не PoD типов данных в shared memory c++

Как изменять не PoD поля в случае использования shared memory? Я так понимаю, что для PoD типов подобный подход "в лоб" работает и на выделенной в mmap памяти поле класса изменяется. Однако поле типа string в данном случае останется неизменным. Каким образом его можно изменить? P.s. Вопрос чисто учебный, так что если вы подведете под ответ некоторую теоретическую базу - будет здорово.
UPD: не PoD поле остается неизменным в parent-процессе. В child-процессе оно-таки меняется, но это порождает еще больше вопросов :)
#include #include #include #include #include #include #include #include
using namespace std;
class human { public: string name; int age; human() { name = '\0'; age = 0; } ~human() {} void set() { cout << "Enter name" << endl; cin >> name; cout << "Enter age" << endl; cin >> age; } void print() { cout << name << " " << age << endl; } };
main(int argc, char * argv[]) { pid_t cpid; char buf; human* shared; human non; shared = (human*)mmap(NULL, sizeof(*shared), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); *shared = non; cpid = fork(); // duplicate the current process if (cpid == 0) // if I am the child then { shared->set(); exit(EXIT_SUCCESS); } else // if I am the parent then { wait(NULL); // wait for the child process to exit before I do the same cout << "Human:" << endl; shared->print(); exit(EXIT_SUCCESS); } return 0; }


Ответ

Нельзя так делать. Сериализуйте данные в разделяемую память, а потом десериализуйте на выходе.
std::string может содержать указатель на внешнюю память, поэтому то, что Вы выделили память под сам объект строки в общей памяти ничего не значит — данные лежат совсем в другом месте.
Конечно, может так совпасть, что оставив код неизменным и изменив строку в одном процессе, это изменение будет видно и в другом, но это частный случай. Вызван он тем, что почти(?) все популярные реализации std::string используют т.н. SSO(small string optimization), при которой вся строка хранится в самом объекте, при её малом размере. Но если записать в строку больше, чем внутренний буфер позволяет, вся строка обязательно будет перемещена в кучу процесса.
После этого, достучаться до этой строки уже не получится так просто. И, попытавшись прочитать или записать что-либо в строку во втором процессе, Вы получите UB, т.к. адрес строки, содержащийся в std::string указывает на область памяти выделенной в первом процессе. В общем случае, во втором процессе этот адрес никем не будет занят, либо будет занят, но совсем другим объектом — в любой из этих ситуаций, обращение к этому адресу как к std::string будет UB(если не совпадёт, конечно, что там окажется другая строка, по точно такому же адресу и такого же размера, но подобные «чудеса» я в рассмотрение не беру.

Если же абстрагироваться от примера, то есть простое правило: если хочешь обменяться данными с любой внешней сущностью(будь то процесс или ещё что-то), сначала сохрани это в каком-то общем для обеих сущностей формате, чтобы принимающая сторона могла безошибочно определить, что ей пришло. Использовать простые объекты C++ языка в такой взаимодействии нельзя, т.к. слишком много мест, где можно «поскользнуться».

Комментариев нет:

Отправить комментарий