I wrote MmapHandler
that provides a shared memory among processes using mmap
and at destruction, it unmaps the shared memory. I want munmap
to be called once by the parent process. However, this unfortunately gets called by all child processes:
MmapHandler.h
:
template<typename T>
class MmapHandler{
protected:
size_t m_size;
T* m_ptr;
public:
MmapHandler(size_t);
~MmapHandler();
}
MmapHandler.cpp
:
template<typename T>
MmapHandler<T>::MmapHandler(size_t size): m_size(size), m_ptr(MAP_FAILED)
{
m_ptr = static_cast<T*>(mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if(m_ptr == MAP_FAILED){
throw std::exception();
}
}
template<typename T>
MmapHandler<T>::~MmapHandler()
{
if(m_ptr != MAP_FAILED)
{
munmap(static_cast<void*>(m_ptr), m_size);
}
}
main.cpp
:
int num_procs = 3;
pid_t pids[num_procs];
MmapHandler sharedMemory(4096);
for(int i=0; i<num_procs; i )
{
if((pids[i] = fork()) < 0){
perror("fork");
}
else if (pids[i] == 0){
// do something with sharedMemory
// ...
//
return 0;
}
}
while(wait(NULL) > 0);
// all children done!
return 0;
If one of the children process exits (e.g. exception), then it destroys the sharedmemory (e.g. munmap). Is there a way I can disable this on my child processes?
I can pass an argument such that only a certain pid can unmap the shared memory, but is there a more elegant C way of doing this?
I thought about =delete
on destructor for child processes only using macros but this obviously won't work...
I also thought about creating a wrapper MmapHandler
class that would =delete
the destructor, and all the other MmapHandler
will be moved to the wrapper handler, but I'm not sure if this'll work.
CodePudding user response:
Why pass an argument, with anyone's pid, somewhere? There's no need to do that.
m_ptr = static_cast<T*>(mmap(NULL, size, PROT_READ, MAP_SHARED, -1, 0);
Here's where you're mmap
ing the memory segment. How about calling getpid()
right here. This gives you your own pid, that you can save somewhere.
T* m_ptr;
It seems logical that the pid_t
would also be saved, right next to the m_ptr
.
munmap(static_cast<void*>(m_ptr), m_size);
And this is where the shared memory segment is getting unmapped. It should now be obvious that calling getpid()
here lets you check if it's the same pid that mapped it, and unmap it only in that case, and do nothing if it's some other process.
Now, nothing outside of this class needs to do anything, and The Right Thing Will Happen.
CodePudding user response:
Store a reference counter in your shared memory; and have the last process free the memory. The counter must be syncronized between processes, so an interprocess counting semaphore may serve the trick.
Iff you can confirm that the grand parent is the last man standing or want to grant it the privilege of ownership of shared memory, you can store the PID of that process inside the constructor, and decide to delete in destructor - based on a comparison to current PID.
Using fork
after using C specific code is often not considered good practice though. system
, spawn
or other utilities such as boost.interprocess might give better results.
Regards, FM.