How to change non-PoD fields when using shared memory? I understand that for PoD types, a similar approach "in the forehead" works and on the field allocated in mmap, the class field changes. However, the string field in this case will remain unchanged. How can it be changed? Ps The question is purely educational, so if you let some theoretical base answer - it will be great.

UPD: no PoD field remains unchanged in the parent process. In the child process, it does change, but it raises even more questions :)

#include <iostream> #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <string.h> 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; } 
  • everything is working. Add a debug-output a little bit to the if: HumanChild: Enter name qqt Enter age 123 Human: 123 . For the compiler do not care pod or not pod, in this case. Plus, because you understand sitting. Also do not cast in a sishny style - I'm talking about (human*) - strangeqargo
  • @strangeqargo I did not fully understand you, but still. I tried to make a conclusion in the child-process, as you said, everything works. But then the question arises: why the output in the parent-process displays only the modified int field? - Shadr
  • @strangeqargo Pro caste thanks for the tip. Share how this is done in with ++? - Shadr
  • cppblogs.blogspot.ru/2013/08/c-style-casts.html , but about the name, yes, you're right. By the way, you make the sizeof an object that can be resized at runtime. We are waiting for the guru, well, or do it yourself. if initialized "by string" and not by 'char', segfolt is strangeqargo
  • @strangeqargo and where was the string initialized? I tried to initialize in the constructor with the string "Who i am?", In parent it gives 'Who i' as the value of the name field. - Shadr

1 answer 1

You can't do that. Serialize the data into shared memory, and then deserialize the output.

std::string can contain a pointer to external memory, therefore, the fact that you allocated memory for the object of the string itself in the shared memory does not mean anything - the data is in a completely different place.

Of course, it can coincide in such a way that leaving the code unchanged and changing the line in one process, this change will be visible in another, but this is a special case. It is caused by the fact that almost (?) All popular implementations of std::string use a so-called. SSO (small string optimization), in which the entire string is stored in the object itself, with its small size. But if you write to the line more than the internal buffer allows, the entire line will be moved to the process heap.

After that, getting to this line is no longer so easy. And, trying to read or write something to the line in the second process, you will get UB, because the address of the string contained in std::string points to the memory allocated in the first process. In the general case, in the second process this address will not be occupied by anyone, or it will be occupied, but by a completely different object — in any of these situations, referring to this address as std::string will be UB (if not the same, of course, there will be another line at the exact same address and the same size, but I don’t take such “miracles” into consideration.


If we abstract from the example, there is a simple rule: if you want to exchange data with any external entity (be it a process or something else), first save it in a format that is common for both entities so that the receiving party can correctly determine what came to her It is impossible to use simple C ++ language objects in such an interaction, since too many places to slip.

  • I understood about serialization, thanks, it sounds quite reasonable. But why it cannot be done in this way is still not clear. And it is not clear why in one process the std :: string field changes, but not in the other. Also it is not clear what is the problem with the pointer to "external memory"? It seemed to me that absolutely no difference where the pointer lies (in shared memory or not) in order to work with this pointer. I would be happy to give you practical comments on these issues. - Shadr
  • @Shadr, because if you allocate shared memory for 2 processes, then only it is available to these processes. In general, 2 processes cannot read each other's memory. std::string , which is allocated in this shared memory has a pointer inside it that points to a block of memory containing characters (that is, the string itself). In general, this memory block is contained in the process heap and is not related to shared memory. Therefore, in order for another process to get to it, it needs to know the address and be able to read the memory of another process. He knows the address, but cannot read (in general). - ixSci
  • if the process cannot read, should there be an error in runtime? It’s just that in the code above there are no errors, both processes successfully display the contents of the string name field (I think it fits the definition of reading, correct me if I am mistaken). - Shadr
  • @Shadr, in your code the potential UB - the program does not have to fall at all, but it can. If it displays the string correctly, it means it gets into the buffer as part of SSO (small string optimization). Enter 40 characters and then you will see that the correct string will be displayed only in the process where it was assigned this value. - ixSci
  • In general, this is what happens, as you say :) And what about UB in what is specifically expressed? - Shadr