2010-03-11 3 views
3

En bref, ma question est: Si vous avez la classe MyClass<T>, comment pouvez-vous changer la définition de classe pour prendre en charge les cas où vous avez MyClass<T, Alloc>, similaire à comment, disons , Le vecteur STL fournit.Ajout d'un allocateur à un modèle de classe C++ pour la création d'objets en mémoire partagée

J'ai besoin de cette fonctionnalité pour prendre en charge un allocateur pour la mémoire partagée. Plus précisément, j'essaie d'implémenter un tampon circulaire dans la mémoire partagée. Actuellement, il a le cteur suivant:

template<typename ItemType> 
SharedMemoryBuffer<ItemType>::SharedMemoryBuffer(unsigned long capacity, std::string name) 

ItemType est le type des données devant être placées dans chaque fente de la mémoire tampon.

Maintenant, cela fonctionne splendide lorsque je crée le tampon du programme principal ainsi

SharedMemoryBuffer<int>* sb; 
sb = new SharedMemoryBuffer<int>(BUFFER_CAPACITY + 1, sharedMemoryName); 

Cependant, dans ce cas, le tampon lui-même est pas créé dans la mémoire partagée et est donc pas accessible à d'autres processus. Ce que je veux faire est d'être en mesure de faire quelque chose comme

typedef allocator<int, managed_shared_memory::segment_manager> ShmemAllocator; 
typedef SharedMemoryBuffer<int, ShmemAllocator> MyBuffer; 

managed_shared_memory segment(create_only, "MySharedMemory", 65536); 
const ShmemAllocator alloc_inst (segment.get_segment_manager()); 
MyBuffer *mybuf = segment.construct<MyBuffer>("MyBuffer")(alloc_inst); 

Cependant, je ne sais pas comment aller sur l'ajout d'un allocateur explicite au modèle de classe.

+0

Je ne comprends pas très bien ce que vous demandez. Avez-vous besoin de savoir comment ajouter un paramètre template à votre template de classe (auquel cas vous devrez probablement montrer la définition actuelle de la classe), ou avez-vous juste besoin de savoir comment construire un objet à un emplacement donné en mémoire (dans ce cas, vous devriez rechercher _placement new_). De toute façon, je serais très prudent de mettre des objets non-POD dans la mémoire partagée. Est-il possible de construire à partir d'un processus et détruire d'un autre? Êtes-vous complètement sûr que tous les membres du groupe peuvent gérer cela? –

+0

Je suppose que ma question peut simplement être paraphrasée comme: comment pouvez-vous créer votre objet dans la mémoire partagée (par opposition à le créer sur le tas en cours et le faire * utiliser * la mémoire partagée.) – recipriversexclusion

+0

Dans ce cas, vous avez besoin de placement. par exemple. si 'shm_addr' est un pointeur' void * 'vers la mémoire partagée, vous pouvez faire' MyBuffer * pBuf = new (shm_Addr) MyBuffer; 'et le nouveau' MyBuffer' sera construit à l'emplacement donné. –

Répondre

3

ce qui me fais confonds est, pourquoi vous avez besoin d'allouer ou de créer un objet dans SharedMemory (SHM), par exemple si vous réservez la mémoire partagée de la taille 65536 octets, supposons que vous obtenez votre mémoire partagée à l'adresse 0x1ABC0000, si le succès de la réservation, vous aurez un espace mémoire libre et directement accessible à 0x1ABC0000 to 0x1ABCFFFF.

alors lorsque votre application a besoin de « allouer » objet SHM de la taille sizeof(SHMObject) et votre gestionnaire de mémoire voir cette adresse à 0x1ABC0000+0x1A est libre, votre gestionnaire de mémoire doit simplement revenir 0x1ABC001A valeur et marquer (0x1ABC001A to 0x1ABC001A+sizeof(SHMObject)) était occupé, et vous venez besoin de lancer: SHMObject* shmObjectPtr = (SHMObject*)(0x1ABC001A);

et bien sûr cela suppose que vous avez votre propre allocateur de mémoire personnalisé qui fonctionne sur une plage spécifiée d'adresse mémoire.

comme pour le modèle, je ne comprends pas vraiment comment votre tampon anneau SHM ressembler, mais je l'ai fait avant d'utiliser SHM, ma mise en œuvre est comme ceci: `

//memory SHM allocator 
template<typename T> class ShmRingAllocator 
{ 
    protected: 
     void* baseAddress; 
    public: 
     ShmRingAllocator(void* baseAddress,int memSize); 
     void* allocate(); //this function do what I described earlier, or you can use placement new: new (baseAddress+offset)T; 
} 

//some kind of shared_ptr<> that handle object in SHM, this provides mechanishm to check is the pointer still valid in shm or not 
template<typname T> ShmRingObjectPtr 
{ 
    protected: 
     T* object; //mapped address of object at current process 
     ShmBuffer* shm; //every object has pointer to which SHM does this pointer pointing at 
    public: 
     virtual T* operator->(); //operator overload to access T object 
} 

class ShmBuffer //base class for all kind of SHM buffer 
{ 
    protected: 
     std::string shmName; 
     void* shmBasePtr; 
} 

template<typename T,class A=ShmRingAllocator<T>> ShmRingBuffer : public ShmBuffer 
{ 
    protected: 
     A allocator; 
    public: 
     ShmRingObjectPtr<T> insert() //push one element to ring buffer 
     { 
       return ShmRingObjectPtr<T>((T*)this->allocator.allocate(),this); 
     } 
} 

`

+0

Votre prototype de tampon SHM est très utile, merci! Je comprends en quelque sorte la façon dont vous l'avez implémenté en utilisant des allocateurs SHM personnalisés. Ce que je ne comprends pas, c'est comment vous accédez à votre ShmBuf à partir de différents processus, un écrivain et un lecteur. Dites, je crée le ShmBuf dans l'écrivain et j'insère des éléments dans celui-ci. Comment un lecteur indépendant peut-il accéder à cet objet et en lire les données (vous ne semblez pas non plus avoir de membre pop()). – recipriversexclusion

+0

Si vous voulez que le processus soit capable d'écrire et de lire, je le résous en créant offset_ptr <> ceci est exactement comme shared_ptr <> mais contient une adresse de pointeur 64 bits (sur la plateforme x86), d'abord il contient l'adresse de base shm En utilisant ceci, vous pouvez utiliser ou écrire un pointeur dans shmBUffer qui pointe vers les données sur shmBUffer, ainsi tous les pointeurs dans shm pointeront vers les mêmes données dans ce shmBuffer, car il utilise le décalage de leur propre base. adresse dans chaque processus. et le reste est à peu près synchrone, puisque vous avez un espace mémoire pratiquement exact entre les processus – uray

4

Je pense que vous recherchez simplement le placement standard nouveau.

Si shm_addr est un pointeur void* à mémoire partagée que vous pouvez faire:

MyBuffer *pBuf = new (shm_Addr) MyBuffer; 

et le nouveau MyBuffer sera construit à l'endroit donné. Cela peut fonctionner avec n'importe quel type d'objet, y compris les types de modèles.

Vous pouvez envelopper dans une fonction séparée si vous le souhaitez.

Pour détruire quelque chose créé avec placement standard, vous devez appeler explicitement le destructeur. C'est parce que delete essayerait de désallouer la mémoire en tant que mémoire allouée new régulière qui ne serait pas une chose valide à faire. C'est la seule fois en C++ que vous devez appeler explicitement un destructeur.

pBuf->~MyBuffer(); 
+0

Je pense que c'est ce que je cherchais. Je ne savais pas que vous pouvez spécifier un emplacement addr pour 'new', wow. Merci! – recipriversexclusion

Questions connexes