boost::interprocess Probleme mit Map und eigener POD Klasse



  • hi!

    ich hoffe, dass mir hier jemand helfen kann - in die boost mailingListe schreibe ich als nicht-experte nicht so gerne 🙂

    ich möchte in einem SharedMemory eine Map erstellen, die als key einen std::string -id- hat und als value ein Objekt meiner POD Klasse RDeviceSyncObject. Mit Hilfe dieser Klasse sollen sich verschiedene Prozesse synchronisieren. Jeder Prozess/Thread, der auf dasselbe Objekt zugreift erhöht den useCounter, sodass ich immer weiß, wieviele Prozesse gerade damit arbeiten (später sollen die Objekte auch gelöscht werden, wenn keiner mehr referenziert - mit dem useCnt ist es für den Anfang um einiges einfacher als einen SharedPointer im SharedMemory zu erstellen).

    Die Methode getRDeviceSyncObject öffnet / erstellt zunächst den SharedMemory, dann wird die Map namens "MyMap" im Shmem geöffnet / erstellt. Wenn der Eintrag in der map schon vorhanden wird, wird der useCoutner erhöht und eine Referenz auf das Objek zurückgegeben. Ansonsten soll der Eintrag in die Map eingefügt werden. Genau dabei habe ich die Probleme in der Zeile mit "map_value_type value(allocIdString, mapped_object);"

    Was mache ich dort falsch? Bin schon den ganzen Tag am suchen / vergleichen . Meine Referenz ist dabei http://www.boost.org/doc/libs/1_40_0/doc/html/interprocess/allocators_containers.html#interprocess.allocators_containers.containers_explained.containers_of_containers

    Vielen Dank für die Mühen!

    martin

    Hier mein (bis auf die eine Zeile kompilierfähiger) Code:

    #include <boost/interprocess/managed_shared_memory.hpp>
    #include <boost/interprocess/allocators/allocator.hpp>
    #include <boost/interprocess/containers/map.hpp>
    #include <boost/interprocess/containers/string.hpp>
    
    typedef unsigned long		U32;
    
     class RDeviceSyncObject
           {
           public:
           	RDeviceSyncObject(){useCounter = 0;};
    
           	~RDeviceSyncObject(){};
    
               boost::interprocess::interprocess_mutex mtxReadWrite;
               boost::interprocess::interprocess_mutex mtxFunction;
    
               U32 locAddrSp0Range;
               U32 locAddrSp0Remap;
               U32 locAddrSp1Range;
               U32 locAddrSp1Remap;
    
               U32 usbInterfaceOwner;
    
               U32 useCounter;
           };
    
        class SharedMemory
          {
          public:
            SharedMemory();
            ~SharedMemory();
    
            RDeviceSyncObject* getRDeviceSyncObject(std::string id);
          };
    
        using namespace boost::interprocess;
    
        const char* MANAGED_SHARED_MEMORY_NAME = "sharedMemoryMapTest";
    
        //Typedefs of allocators and containers
        typedef managed_shared_memory::segment_manager						segment_manager_t;
        typedef allocator<void, segment_manager_t>							void_allocator;
        typedef allocator<char, segment_manager_t>          				char_allocator;
        typedef basic_string<char, std::char_traits<char>, char_allocator>	char_string;
    
        typedef allocator<RDeviceSyncObject, segment_manager_t>             MyRDeviceSyncObject;
    
        //Definition of the map holding a string as key and RDeviceSyncObject as mapped type
        typedef std::pair<const char_string, RDeviceSyncObject>			map_value_type;
        typedef std::pair<char_string, RDeviceSyncObject>				movable_to_map_value_type;
        typedef allocator<map_value_type, segment_manager_t>			map_value_type_allocator;
        typedef map< char_string, RDeviceSyncObject
        , std::less<char_string>, map_value_type_allocator>	RDeviceSyncObject_map_type;
    
        SharedMemory::SharedMemory()
        {
        }
    
        SharedMemory::~SharedMemory()
        {
        }
    
        RDeviceSyncObject* SharedMemory::getRDeviceSyncObject(std::string id)
        {
          managed_shared_memory segment(open_or_create, MANAGED_SHARED_MEMORY_NAME, 65536);
    
          //An allocator convertible to any allocator<T, segment_manager_t> type
          void_allocator alloc_inst (segment.get_segment_manager());
    
          //Construct the shared memory map and fill it
          RDeviceSyncObject_map_type *mymap = segment.find_or_construct<RDeviceSyncObject_map_type>
                                              //(object name), (first ctor parameter, second ctor parameter)
                                              ("MyMap")(std::less<char_string>(), alloc_inst);
    
          char_string allocIdString(id.c_str(), alloc_inst);
          RDeviceSyncObject_map_type::iterator iter = mymap->find(allocIdString);
          if( iter == mymap->end() )  // Id is not in Map. Insert it!
            {
              MyRDeviceSyncObject mapped_object(alloc_inst);
              map_value_type value(allocIdString, mapped_object);
    
              //Modify values and insert them in the map
              //mymap->insert(value);
            }
    
          // the requested id is now in the list!
          iter = mymap->find(allocIdString);
          iter->second.useCounter++;
    
          return &(iter->second);
        }
    
        int main()
        {
        	SharedMemory shm;
        	shm.getRDeviceSyncObject("idName")->mtxFunction.lock();
    
        	shm.getRDeviceSyncObject("idName")->mtxFunction.unlock();
    
    		shm.getRDeviceSyncObject("idName2")->mtxFunction.lock();
    
            return 0;
        }
    

  • Administrator

    Lies doch mal die Fehlermeldung, welche du im übrigen nicht angegeben hast, obwohl es das Wichtigste ist. Zum Beispiel unter VS2008:

    1>c:\...(87) : error C2664: 'std::pair<_Ty1,_Ty2>::pair(_Ty1 &,const _Ty2 &)' : cannot convert parameter 2 from 'MyRDeviceSyncObject' to 'const RDeviceSyncObject &'
    1>        with
    1>        [
    1>            _Ty1=const char_string,
    1>            _Ty2=RDeviceSyncObject
    1>        ]
    1>        Reason: cannot convert from 'MyRDeviceSyncObject' to 'const RDeviceSyncObject'
    1>        No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
    

    Das sollte dir schon alles sagen und dich auf den richtigen Weg bringen. Du erstellst ein MyRDeviceSyncObject (im übrigen ein völliger blöder Name, weil es ein std::allocator ist) und willst dieses Objekt dann einer Funktion übergeben, welche ein RDeviceSyncObject erwartet.

    Zudem sollte ich dir wohl noch sagen, dass laut aktuellem Standard RDeviceSyncObject kein POD ist.

    Grüssli

    PS: Weisst du eigentlich, was du da machst? 🙂



  • hi!

    Danke für deine Antwort. Die Fehlermeldung hatte ich nicht gepastet, weil die in eclipse länger als 2 Monitorhöhren war.
    Mittlerweile habe ich auch VS2008 installiert und siehe da: man bekommt die von dir eingefügte Fehlermeldung, die auch verständlich ist 🙂

    Dravere schrieb:

    Zudem sollte ich dir wohl noch sagen, dass laut aktuellem Standard RDeviceSyncObject kein POD ist.

    Grüssli

    PS: Weisst du eigentlich, was du da machst? 🙂

    hab POD nochmal nachgelesen - du hast vollkommen Recht (http://en.wikipedia.org/wiki/Plain_old_data_structures):

    Plain old data structures (PODS) are data structures that are represented only as passive collections of field values, without using encapsulation or other object-oriented features.

    Habe also ein "normales C++ Objekt" und keine POD.

    hehe und "was ich da genau mache": ehrlich gesagt noch nicht. Kämpfe mich seit Tagen durch die (für mich sehr komplexe) boost::interprocess Doku und komme nur sehr langsam vorwärts (bin noch relativ unerfahren in c)

    Eine weitere Frage habe ich noch. Mein Code sieht jetzt so aus:

    #include <iostream>
    
    #include <boost/interprocess/managed_shared_memory.hpp>
    #include <boost/interprocess/allocators/allocator.hpp>
    #include <boost/interprocess/containers/map.hpp>
    #include <boost/interprocess/containers/string.hpp>
    
    typedef unsigned long		U32;
    
     class RDeviceSyncObject
           {
           public:
           	RDeviceSyncObject(){useCounter = 0;};
    
           	~RDeviceSyncObject(){};
    
               boost::interprocess::interprocess_mutex mtxReadWrite;
               boost::interprocess::interprocess_mutex mtxFunction;
    
               U32 locAddrSp0Range;
               U32 locAddrSp0Remap;
               U32 locAddrSp1Range;
               U32 locAddrSp1Remap;
    
               U32 usbInterfaceOwner;
    
               U32 useCounter;
           };
    
        class SharedMemory
          {
          public:
            SharedMemory();
            ~SharedMemory();
    
            RDeviceSyncObject* getRDeviceSyncObject(std::string id);
          };
    
        using namespace boost::interprocess;
    
        const char* MANAGED_SHARED_MEMORY_NAME = "sharedMemoryMapTest";
    
        //Typedefs of allocators and containers
        typedef managed_shared_memory::segment_manager						segment_manager_t;
        typedef allocator<void, segment_manager_t>							void_allocator;
        typedef allocator<char, segment_manager_t>          				char_allocator;
        typedef basic_string<char, std::char_traits<char>, char_allocator>	char_string;
    
        typedef allocator<RDeviceSyncObject, segment_manager_t>             RDeviceSyncObject_allocator;
    
        //Definition of the map holding a string as key and RDeviceSyncObject as mapped type
        typedef std::pair<const char_string, RDeviceSyncObject>			map_value_type;
        typedef std::pair<char_string, RDeviceSyncObject>				movable_to_map_value_type;
        typedef allocator<map_value_type, segment_manager_t>			map_value_type_allocator;
        typedef map< char_string, RDeviceSyncObject
        , std::less<char_string>, map_value_type_allocator>	RDeviceSyncObject_map_type;
    
        SharedMemory::SharedMemory()
        {
        }
    
        SharedMemory::~SharedMemory()
        {
        }
    
        RDeviceSyncObject* SharedMemory::getRDeviceSyncObject(std::string id)
        {
          managed_shared_memory segment(open_or_create, MANAGED_SHARED_MEMORY_NAME, 65536);
    
          //An allocator convertible to any allocator<T, segment_manager_t> type
          void_allocator alloc_inst (segment.get_segment_manager());
    
          //Construct the shared memory map and fill it
          RDeviceSyncObject_map_type *mymap = segment.find_or_construct<RDeviceSyncObject_map_type>
                                              //(object name), (first ctor parameter, second ctor parameter)
                                              ("MyMap")(std::less<char_string>(), alloc_inst);
    
          char_string idStr(id.c_str(), alloc_inst);
          RDeviceSyncObject_map_type::iterator iter = mymap->find(idStr);
          if( iter == mymap->end() )  // Id is not in Map. Insert it!
            {
            //  RDeviceSyncObject mapped_object(alloc_inst);
              map_value_type value(idStr, RDeviceSyncObject());
    
              //Modify values and insert them in the map
    		  mymap->insert(boost::interprocess::move(map_value_type(idStr, RDeviceSyncObject())));
            }
    
          // the requested id is now in the list!
          iter = mymap->find(idStr);
          iter->second.useCounter++;
    
          return &(iter->second);
        }
    
        int main()
        {
        	SharedMemory shm;
        	shm.getRDeviceSyncObject("idName")->mtxFunction.lock();
    
        	shm.getRDeviceSyncObject("idName")->mtxFunction.unlock();
    
            return 0;
        }
    

    Beim Kompilieren bekomme ich:

    d:\dev\svn_raptorsuite_kaiserm\shmemtest\src\shmemtest.cpp(29) : error C2248: 'boost::interprocess::interprocess_mutex::interprocess_mutex' : cannot access private member declared in class 'boost::interprocess::interprocess_mutex'
    d:\dev\svn_raptorsuite_kaiserm\common\lib\boost_1_39_0\include\boost\interprocess\sync\interprocess_mutex.hpp(70) : see declaration of 'boost::interprocess::interprocess_mutex::interprocess_mutex'
    d:\dev\svn_raptorsuite_kaiserm\common\lib\boost_1_39_0\include\boost\interprocess\sync\interprocess_mutex.hpp(67) : see declaration of 'boost::interprocess::interprocess_mutex'
    This diagnostic occurred in the compiler generated function 'RDeviceSyncObject::RDeviceSyncObject(const RDeviceSyncObject &)'
    d:\dev\svn_raptorsuite_kaiserm\shmemtest\src\shmemtest.cpp(29) : error C2248: 'boost::interprocess::interprocess_mutex::interprocess_mutex' : cannot access private member declared in class 'boost::interprocess::interprocess_mutex'
    d:\dev\svn_raptorsuite_kaiserm\common\lib\boost_1_39_0\include\boost\interprocess\sync\interprocess_mutex.hpp(70) : see declaration of 'boost::interprocess::interprocess_mutex::interprocess_mutex'
    d:\dev\svn_raptorsuite_kaiserm\common\lib\boost_1_39_0\include\boost\interprocess\sync\interprocess_mutex.hpp(67) : see declaration of 'boost::interprocess::interprocess_mutex'
    This diagnostic occurred in the compiler generated function 'RDeviceSyncObject::RDeviceSyncObject(const RDeviceSyncObject &)'

    Wie ich das sehe, sind die copy Konstruktoren in den interprocess Mutexen private. Wie bekomme ich das hin, dass ich das Objekt direkt (ohne umkopieren) in die map einfüge?

    Vielen Dank nochmal!

    Martin


  • Administrator

    madding3w schrieb:

    Danke für deine Antwort. Die Fehlermeldung hatte ich nicht gepastet, weil die in eclipse länger als 2 Monitorhöhren war.

    Ist aber trotzdem etwas vom wichtigsten. Wenn sie für dich unverständlich ist, heisst dies nicht, dass sie auch für andere unverständlich ist. Der GCC, und ich nehme mal an, dass du diesen mit Eclipse verwendet hast, hat zum Teil recht kryptische Fehlermeldungen. Wobei man muss die Fehlermeldungen nur mal in Ruhe durchlesen, dann sind sie lesbar. Das lesbare Zeug ist meistens ein wenig verstreut und kommt nicht direkt aufeinander, weil dazwischen gewisse seltsame Bezeichner vorkommen.

    madding3w schrieb:

    hehe und "was ich da genau mache": ehrlich gesagt noch nicht. Kämpfe mich seit Tagen durch die (für mich sehr komplexe) boost::interprocess Doku und komme nur sehr langsam vorwärts (bin noch relativ unerfahren in c)

    Zwei Sachen hierzu:
    1. Es gibt einen Unterschied zwischen C, C++, C#, C++/CLI und was es sonst noch für C@ (@ hier als Platzhalter) gibt. Das sind alles unterschiedliche Sprachen, wenn du also von C++ redest, dann schreib auch C++ hin 😉
    2. Du bist also unerfahren in C++, folglich nehme ich an, dass du noch nicht lange in C++ programmierst, womöglich erst noch am Üben? Ist es dann nicht etwas verfrüht bereits mit Boost.Interprocess anzufangen? Vielleicht zuerst mal sauber C++ erlernen? Und das heisst für mich nicht nur die Grundlagen zu können 🙂

    madding3w schrieb:

    Wie ich das sehe, sind die copy Konstruktoren in den interprocess Mutexen private. Wie bekomme ich das hin, dass ich das Objekt direkt (ohne umkopieren) in die map einfüge?

    Ja, Mutex sind normalerweise nie kopierbar, weil es nicht all zu viel Sinn macht ein Mutex zu kopieren, bzw. man nicht definieren kann, was dann genau passieren soll.
    Eine Möglichkeit wäre, dass du deine Objekte auf dem Heap anlegst und sie dann in der Map als Zeiger speicherst. Du musst dann aber nicht vergessen aufzuräumen. Dafür hilfreich wären vielleicht die Boost.PointerContainer oder Boost.SmartPointer. Allerdings befürchte ich, dass dich dies dann gleich komplett überfordern wird 🙂

    Deshalb solltest du eben C++ nicht nur in den Grundlagen beherrschen. Vielleicht solltest du auch einfach C++ zuerst mit kleineren Programmen angehen, bzw. um deine Erfahrung auszubauen. Schritt für Schritt 😉

    Grüssli


Anmelden zum Antworten