Как изменять не PoD поля в случае использования shared memory? Я так понимаю, что для PoD типов подобный подход "в лоб" работает и на выделенной в mmap памяти поле класса изменяется. Однако поле типа string в данном случае останется неизменным. Каким образом его можно изменить?
P.s. Вопрос чисто учебный, так что если вы подведете под ответ некоторую теоретическую базу - будет здорово.
UPD: не PoD поле остается неизменным в parent-процессе. В child-процессе оно-таки меняется, но это порождает еще больше вопросов :)
#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++ языка в такой взаимодействии нельзя, т.к. слишком много мест, где можно «поскользнуться».
Комментариев нет:
Отправить комментарий