I have 2 applications that are using a shared memory segment to pass data from a writing process to a reading process. At the top of the shared memory segment, I want to declare a single header struct to contain general segment data such as buffer count values, read/write offsets, pthread mutex/condition variables, etc. The header struct does NOT contain any pointers. Then the rest of the segment is used for the actual data being passed between the 2 processes.
Since the shared memory segment is attached to the process, I am assured that the segment is indeed valid/accessible to the process. It is easy to simply cast the base segment pointer to a pointer of the header struct type and that works very well for regular data types (like ints, etc) but does not work for the non-integral data types in the struct like pthread mutex/condition variables since they have not actually been declared and allocated.
So, how do I declare and allocate my header struct to start at the specific address of my already allocated shared memory segment?
The following does not appear to work:
SmHeader header = *((SmHeader *)m_pBaseAddress);
m_pHeader = &header;
where SmHeader is a typedef of my header struct and m_pBaseAddress is the base address of the attached shared memory segment.
thanks,
-Andres
I think it doesn't work because of the way you're creating it:
// this creates a copy of the SmHeader struct, on the stack
SmHeader header = *((SmHeader *)m_pBaseAddress);
// this sets m_pHeader to address of the local variable, not
// m_pBaseAddress
m_pHeader = &header;
Try this instead:
m_pHeader = (SmHeader *) m_pBaseAddress;
Related
In this topic Two variables in one shared memory , you can see how to put 2 variables into one shared memory in C.
However, I want to put multiple variables into one shared memory using MapViewOfFile function.
But there's no example or solution I've found.
Types of variables are different so I can't use std::vector nor array.
How should I set arguments of CreateFileMapping and MapViewOfFile to do this?
How can I get and set an address in FileMapping which I want to read and write a variable?
It shouldn't be needed that I have to create a FileMapping for each variables, right?
Use a struct as davetherock pointed out.
You have to specify the total size of all the members for "CreateFileMapping" and for "MapViewOfFile". Then you can cast the return void pointer of MapViewOfFile to the structure pointer type.
For example, if you have a struct like
typedef struct combinedStruct {
int intVariable;
float floatVariable;
}CombinedStruct;
You have to create a pointer of type CombinedStruct and cast the return of MapViewOfFile.
CombinedStruct * structPtr = (CombinedStruct*)(MapViewOfFile(...));
Then you can access the individual variables like structPtr->intVariable and structPtr->floatVariable
This may be better suited as comment but i do not have enough reputation to comment.
I am also looking for the answer for this same question and i did as said by #Manoj AV , with one change-
In the CopyMemory Instead of retrieving it as structPtr->intVariable and structPtr->floatVariable i used structPtrfor first variable and structPtr+1 to retrieve the second variable in the structure and so on.And it runs successfully.
The easiest way to have two variables back-to-back in the same chunk of memory is to use a Struct: typedef struct vs struct definitions.
If you'd like to use shmget, you simply must adjust the size of the memory allocated
shmid = shmget (shmkey, sizeof(var1) + sizeof(var2), 0644 | IPC_CREAT);
Then, adjust the pointers as necessary.
I have a 'program' that runs as multiple independent processes that use POSIX semaphores and shared memory to store and share common variables with each other. The problem is that so far this has been implemented as a main program which sets the initial values of the variables in shared memory, and the other programs rely on getting the address offset right to access a given variable.
I would like to improve on this design. An idea I had was to bundle together all methods for access to shared memory in a shared library, and have perhaps an enum as an argument to a GetVariable method, something like this
enum class SHMVariables: long
{
kVariable1 = address_offset_of_variable_1,
kVariable2 = address_offset_of_variable_2,
...
}
template <class T>
void GetVariable(SHMVariables var, T &)
{
// lock semaphore, do some memory boundary checks, and return the value of the variable
}
The challenge is that the variables may have different arithmetic types (some are user-defined structs with arithmetic type members) and I'm wondering what a best approach could be to manage type-safety. Could a map do the trick?
std::map<SHMVariables, std::size_t> // the value being assigned with something like sizeof(struct foo)
What are best practices when it comes to managing variables of different type in shared memory? Is shared memory even an appropriate choice?
I have a situation where I need to send an object (which has pointers to dynamically allocated objects) from one process to anther process via IPC.
Blueprint of the class is:
class Example
{
std::string str;
char *cstring;
int value;
};
As you can see it has dynamically allocated data members that points to heap area mapped into that process.
If it was static object members then they are mapped in continuous memory allocation, and we can mem copy that object, right ? May be I am wrong or missing something.
Can we copy this entire object and send it over IPC, using any of the IPC mechanisms ?
Hope anyone of you can share some details how it will work or can be made to work by pointing me in right direction.
Thanks
Generally you need to serialise it into a sequential byte buffer, similar to how you might write or read say a file or over a network/internet. There are various libraries to help you with this, either with binary formats, or structured text like JSON or XML. Some may generate the boilerplate code for you to convert to and from structs or classes.
If you are using shared memory at the same virtual address, you could possibly take advantage of custom allocators to make sure STL types and other things store everything also in shared memory. I am not sure if the standard says anything much on if such use of shared memory for standard defined objects is technically compliant. I would expect string, vector, etc. to work, while things like mutex, fstream, etc. won't.
I have read the article about Memory-Mapped Files and the example about CreateFileMapping.
My question is: Can I pass a pointer to a struct or a object between two processes using memory-mapped file?
Since there are some answers that it is possible, here is struct that I want to pass:
// First Process
struct OtherStruct{};
struct MyStruct
{
unsigned long handleObject;
unsigned long *phandleObject;
OtherStruct someData;
OtherStruct *pData;
}
MyStruct dataSend = { ... };
WriteToMappedFile(data);
// Second Process
MyStruct dataReceived = ReadFromMappedFile()
As the other answers already stated, you must either rely on the address of the memory-mapped areas to be equal, or you must move from absolute addresses in your pointers to relative addressing.
One possible implementation I stumbled across recently is the offset_ptr in the Boost library, which seems to fit your use case perfectly.
The answer depends on what you want to achieve. Passing a pointer in shared memory is easy, but the other process may not be able to use it in the way you expect.
Note that a pointer contains a virtual address of the data structure it points to. Such a virtual address is only valid within the process that holds the pointed-to data structure. If you pass the pointer to another process, the other process will have its own virtual address space, and the passed pointer loses its validity.
So the answer to your question is: Yes, you can pass the pointer, but without further actions, you won't be able to successfully use this pointer in the receiving process. Specifically, you will most probably not be able to use it for accessing the struct or object it points to.
If you want to access the struct or object within the other process, you need to do the following:
Put the object itself into shared memory.
Convert the pointer to the object into an offset relative to the beginning of the memory mapped file.
Pass this offset to the other process
In the other process, use the offset to convert back to a pointer.
boost::offset_ptr can help you with part of that.
Assuming the Pointer is to a struct that is part of the same memory mapped region, yes that can make sense. but then you will have to ensure that the memory mapped region is mapped to the same virtual address, this is not always guaranteed and is a bad way to design things.
You can pass the offset instead and deal with relative offsets everywhere fpor structures present in this memory region.
If the pointer you want to pass into the memory-mapped-file is not allocated by GlobalAlloc, and not locked by GlobalLock, it can't. However, you have already the memory allocated to pass the data. So you can re-write the memory on the memory-mapped-file.
I have this simple struct defined at the top of my cpp file:
struct sServersArray
{
TCHAR sName[128];
};
struct sServersArray sServers[1024] = {0};
What I do is store data into the .Name field in one function, and read the data in other functions.
I know this is taking up valuable memory (off of the stack/heap, I don't know which or why), and I know it should be moved somehow - to a class perhaps?
Can someone show me how to move this struct to a class and be able to have my other functions access it? I am concerned about using too much stack/heap space and know this is the wrong way to go about doing this. Thanks!
struct sServersArray
{
std::string sName;
};
std::vector<sServersArray> sServers;
Global data is allocated in a separate section of memory, not the stack, not the "heap" (free store).
Simple solution: read server names to an std::vector<std::string> and pass that around by reference. That way, your data is allocated on the heap, there are no more globals to worry about and you get rid of the arbitrary length restrictions.
(You could also create a global vector, but please don't do that. Global data is a code smell.)