My original question is here, which no one seems interested in.
I’ve decided to break that tedious question down and to ask the following:
char* shared_memory;
shared_memory = (char*) shmat (segment_id, 0, 0);
Do we typically get the pointer to the shared memory like the example above? In other words, should we always cast the pointer to char* or whatever better fits our needs?
I don’t know exactly about
shmat, but I have some experience with the WinAPI equivalent (MapViewOfFile, so I will give a more general answer.Because you tied your two questions together, and the other question is about C++ objects in shared memory, I’ll handle both C and C++ cases here. I invite you to add the [c++] tag to your question.
Memory and Shared Memory
Whatever the API, you’ll end up getting a
void *because it is what it is: An address to some memory zone (shared or not).That “allocation API” (either malloc, shmat, MapViewOfFile, etc.) has no idea what you’ll do with that memory, what abstractions you’ll use (C structs, C++ objects, even C macros or built-in types), so the only thing that API can do is to give you:
void *The problem is: What you’ll do with that memory?
There’s no way you can access the content of that memory through the
void *, because you can’t dereference avoid *(it is, after all, a pointer tovoid…). Avoid *only contains an address. Nothing more, nothing less.The
charabstractionThe first abstraction you’ll find, the easiest one, is the
charabstraction. There is nobytetype in C and C++, and thechar(orunsigned char) type fills the role. So, if you want to access that memory as an array of bytes, you cast the return of that memory intochar:The
structabstractionThe second abstraction is to assume the shared memory is a struct (or perhaps even an array of struct), so you should cast the pointer into a pointer to that struct:
Thus, you can access that shared memory through the struct.
Concurrency?
Worst case: Two processes will working simultaneously. So if you don’t use synchronization primitives (like an interprocess mutex), you’ll fall into race conditions (one process writing a value, while the other is reading it, potentially leading to corrupted read data)
About shared memory and pointers
Usually, shared memory is used to be shared between processes. Usually, this means that the API can (and will probably) return for the same shared memory different addresses for each process.
The reasons are somewhat complicated (and should be their own question), but here it is: Two processes with pointers to the same memory won’t have the same addresses on their respective pointers.
Addresses are useless in shared memory. If you put a valid pointer address from the process A in a shared memory, that pointer address will be invalid in the process B. So, never put addresses.
What you can put in shared memory is indices. For example, you could have the struct:
With this struct, you could set a value 3.1415 in the
valuearray, at the index 42:And then retrieve it in the other process:
About C and C++
This shared memory thing is an API problem, not a C or C++ specific problem.
In your original question, you mentioned C++ objects in shared memory, so I’ll detail some differences in C and C++ that have been reported despite being outside the true scope of your question.
C casts vs. C++ casts
In C, it is legal to implicitly cast any
void *pointer into any kind of pointerT *. In C++, you need a static cast for that:So usually, to produce C/C++ compatible code, most people will use the C-style cast which is common to the two languages, with invariably incurring language lawyers’s remarks (I am guilty of that).
Despite heated debates, the truth is that each language is right because despite their strong similarities and common grounds, they are different in one major domain: C is a weakly typed language, whereas C++ is a strongly typed language.
Putting C++ object in shared memory
Remember the part where I wrote that you should not put pointers in shared memory?
This is true for C and C++: The moment you have a pointer instead of a relative index in shared memory, you have a probable problem (i.e. a probable bug).
So, if you put in shared memory a struct with a pointer member containing an address in process A, that address will be invalid in process B.
C++ objects offer a strong abstraction, meaning they are easy and safe to use (there’s no memory leaks risks when using
std::stringorstd::vector<std::string> objectsdespite the amount of memory allocation involved, for example). But this strong abstraction only hides the fact that inside, you still do have pointers…The second difficulty with C++ objects in shared memory is that construction and destruction must be handled manually (using placement new and explicit destructor call).
Conclusion: Unless you know the object you’re using can handle it, and you used that object correctly, writing the following cast:
will not work correctly with pointers to shared memory.