Search code examples
boostinterprocess

boost:interprocess > managed_shared_memory > different values


I would like to understand the behavior of the following code.

IDAInterface is a libary with a member "myValue".

C++:

#include <boost/interprocess/managed_shared_memory.hpp>
#include <cstdlib>

#include <idainterface.h>

IDAInterface ifIDA;

int main(int argc, char *argv[])
{
   using namespace boost::interprocess;
   typedef std::pair<IDAInterface, int> MyType; // [1]

   if(argc == 1){  //Parent process
      struct shm_remove{
         shm_remove() { shared_memory_object::remove("MySharedMemory"); }
         ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); }
      } remover;
      ifIDA.myValue = 15;
      managed_shared_memory segment(create_only, "MySharedMemory", 65536);
      MyType *instance = segment.construct<MyType> ("MyType instance") (ifIDA, 0);
      std::string s(argv[0]); s += " child ";
      if(0 != std::system(s.c_str())) return 1;
      std::cout<<"\nPROZESS 1  "<< ifIDA.myValue;
      std::cout.flush();
      //std::cout<<"\nPROZESS 1  "<< instance->first.myValue;
      //std::cout.flush();
      //segment.destroy<MyType>("MyType instance");
      if(segment.find<MyType>("MyType instance").first) return 1;
   }
   else{
      managed_shared_memory segment(open_only, "MySharedMemory");
      std::pair<MyType*, managed_shared_memory::size_type> res;
      res = segment.find<MyType> ("MyType instance");
      if(res.second != 1) return 1;
      IDAInterface nIFIDA;
      nIFIDA = res.first->first;
      std::cout<<"\nPROZESS 2  "<< nIFIDA.myValue;
      std::cout.flush();
      nIFIDA.EineZahl = 10;
      std::cout<<"\nPROZESS 2  "<< nIFIDA.myValue;
      std::cout.flush();
      segment.destroy<MyType>("MyType instance");
   }
   return 0;
} 

The output:

PROZESS 2 15

PROZESS 2 10

PROZESS 1 15

PROZESS 1 15

As I understood should be the value in process 1, after running process 2, also 10. Why is in process 1 the value of "myValue" always 15? And how to get the modified value of "myValue" through process 2 in process 1?


Solution

  • I believe the basic understanding of Boost.Interprocess is correct, but the implementation is wrong. In this case, process 2:

    • Constructs a local copy of IDAInterface from the shared IDAInterface instance. Changes to the local copy will not be observed by other processes.
    • Modifies the wrong member variable. Process 1 is checking myValue, but Process 2 modifies EineZahl.

    Another point to note is it that when using segment_manager::find(), the return value's first member variable should be checked for non-null to determine if the instance was found. In the case where the instance was not found, the second member variable will be 1.


    Here is a complete example where Process 1 creates an integer in a shared memory segment, setting the value to 15. Process 1 will then spawn Process 2, who will attach to the shared memory segment, locate the integer, and change its value to 10. Once Process 2 exits, Process 1 prints the modified value.

    #include <cstdlib>
    #include <iostream>
    
    #include <boost/interprocess/managed_shared_memory.hpp>
    
    const char* segment_name = "MySharedMemory";
    const char* instance_name = "MyType instance";
    typedef int my_type;
    
    int parent_main(const std::string& process)
    {
      using namespace boost::interprocess;
      struct shm_remove {
         shm_remove() { shared_memory_object::remove(segment_name); }
         ~shm_remove(){ shared_memory_object::remove(segment_name); }
      } remover;
    
      // Create memory segment.
      managed_shared_memory segment(create_only, segment_name, 65536);
    
      // Create an instance of my_type with a value of 15 in the shared segment.
      my_type* instance = segment.construct<my_type>(instance_name)(15);
    
      // Print value before child.
      std::cout << "p1 - before child: " << *instance << std::endl;
    
      // Spawn child.
      std::string command = process + " child";
      if (0 != std::system(command.c_str())) return 1;
    
      // Child has exited, so print the shared instance value.
      std::cout << "p1 - after child: " << *instance << std::endl;
      return 0;
    }
    
    int child_main()
    {
      using namespace boost::interprocess;
      // Attach to shared memory segment.
      managed_shared_memory segment(open_only, segment_name);
    
      // Find the my_type instance in the segment.
      my_type* instance = segment.find<my_type>(instance_name).first;
    
      // If the instance was not found, then return early.
      if (!instance) return 1;
    
      // Value before modifying (initial value set by parent).
      std::cout << "p2 - begin child: " << *instance << std::endl;
    
      // Modify and print value.
      *instance = 10;
      std::cout << "p2 - end child: " << *instance << std::endl;
      return 0;
    }
    
    int main(int argc, char *argv[])
    {
      return (1 == argc) ? parent_main(argv[0]) : child_main();
    }
    

    Output:

    p1 - before child: 15
    p2 - begin child: 15
    p2 - end child: 10
    p1 - after child: 10