2011-01-06 19 views
9

mi chiedevo come condividere un ricordo tra i diversi moduli di programma - consente di dire, ho un ricorso principale (exe), e poi alcuni moduli (dll). Entrambi collegano alla stessa libreria statica. Questa libreria statica avrà qualche manager, che fornisce vari servizi. Quello che mi piacerebbe ottenere, è avere questo gestore condiviso tra tutti i moduli dell'applicazione, e farlo in modo trasparente durante l'inizializzazione della libreria. Tra i processi potrei usare la memoria condivisa, ma voglio che questo sia condiviso solo nel processo corrente. Potresti pensare ad un modo multipiattaforma per fare questo? Possibilmente usando le librerie di boost, se forniscono alcuni servizi per farlo.condivisione della memoria tra i moduli

unica soluzione che viene in mente in questo momento, è quello di utilizzare libreria condivisa del rispettivo sistema operativo, che tutti gli altri moduli si collegherà a in fase di esecuzione, e hanno salvato il manager lì.

EDIT: chiarire che cosa ho effettivamente bisogno:

  1. Ho bisogno di scoprire, se il gestore condiviso è già stato creato (le risposte di seguito già previsti alcuni modi per farlo)
  2. Prendi il puntatore al gestore, se esiste, oppure Imposta il puntatore da qualche parte sull'oggetto gestore appena creato.
+0

Dato che si tratta di un singolo processo, in che modo si differenzia da un normale schema di singleton? – sdg

+0

È in effetti un singleton, il problema è come implementarlo, quindi sarà condiviso tra diverse librerie condivise. –

+0

All'interno dello stesso processo, qualsiasi modulo può accedere a variabili globali esterne senza alcuna restrizione. – 9dan

risposta

11

penso che si sta andando ad avere bisogno di assistenza da parte di una libreria condivisa per fare questo in qualsiasi modo portatile. Non ha necessariamente bisogno di sapere nulla sugli oggetti condivisi tra i moduli, ma deve solo fornire una mappatura accessibile a livello globale da una chiave (probabilmente una stringa) a un puntatore.

Tuttavia, se si desidera chiamare le API del sistema operativo, ciò è fattibile e penso che potrebbero essere necessarie solo due implementazioni della parte specifica del sistema operativo (una per le DLL di Windows e GetProcAddress, una per i sistemi operativi che utilizzano dlopen) .

Come ogni carichi di moduli, cammina la lista dei moduli caricati in precedenza alla ricerca di quelle che esportano una funzione appositamente nominata. Se ne trova uno (qualsiasi, non importa quale, perché l'invariante è che tutti i moduli completamente caricati sono consapevole dell'oggetto comune), si ottiene l'indirizzo dell'oggetto comune dal modulo precedentemente caricato, quindi incrementa il conteggio di riferimento . Se non riesce a trovarne, assegna nuovi dati e inizializza il conteggio dei riferimenti. Durante lo scaricamento del modulo, decrementa il conteggio dei riferimenti e libera l'oggetto comune se il conteggio dei riferimenti ha raggiunto lo zero.

Ovviamente è necessario utilizzare l'allocatore del sistema operativo per l'oggetto comune, perché sebbene sia improbabile, è possibile che sia stato deallocato da una libreria diversa da quella che lo ha caricato per la prima volta. Ciò implica anche che l'oggetto comune non può contenere alcuna funzione virtuale o qualsiasi altro tipo di puntatore ai segmenti dei diversi moduli. Tutte le sue risorse devono essere allocate dinamicamente utilizzando l'allocatore del processo del sistema operativo. Questo è probabilmente meno oneroso per i sistemi in cui libC++ è una libreria condivisa, ma hai detto che stai collegando staticamente il CRT.

funzioni necessarie in Win32 includerebbe EnumProcessModules, GetProcAddress, HeapAlloc, e HeapFree, GetProcessHeap e GetCurrentProcess.

Tutto considerato, penso che mi limiterei a inserire l'oggetto comune nella propria libreria condivisa, che sfrutta le strutture di dati del caricatore per trovarlo. Altrimenti stai reinventando il caricatore. Questo funzionerà anche quando il CRT è collegato staticamente a diversi moduli, ma penso che tu ti stia preparando per le violazioni ODR. Sii molto particolare riguardo alla conservazione dei dati comuni POD.

+0

Bene, questa è una soluzione davvero creativa :-) Mi chiedo se l'eseguibile dell'applicazione si collega ad alcune librerie condivise (automaticamente all'avvio) e allo stesso tempo ha alcune variabili globali definite, è l'ordine di caricamento delle librerie/inizializzazione globale variabili definite dallo standard o la sua implementazione è definita? Se i dati globali vengono inizializzati per primi, allora possiamo eseguire l'inizializzazione nell'eseguibile principale e non preoccuparti dei diversi allocatori di memo in caso di collegamento CRT statico. –

+1

@John: Oh, stai garantendo che queste variabili esistano nell'eseguibile principale? Ho pensato che stavi progettando per il caso generale: provare a costruire una libreria che funzioni sia che l'applicazione usi lo stesso oggetto helper oppure no. Ad ogni modo, le librerie non sono indirizzate dallo standard C++ AT ALL, quindi in particolare l'ordine di caricamento non è definito dallo standard. Tuttavia, sulla maggior parte delle piattaforme le librerie vengono gestite dal caricatore del sistema operativo prima dell'esecuzione di qualsiasi costruttore.Ovviamente con caricamento ritardato o caricamento esplicito le librerie non si caricano durante l'avvio ma quando viene eseguito quel codice. –

+0

Sì, la biblioteca dovrebbe essere generica, quindi era solo un pensiero. –

0

È possibile utilizzare boost::interprocesshttp://www.boost.org/doc/libs/1_45_0/doc/html/interprocess.html e su Windows è possibile creare un segmento condiviso nella DLL che sarà condivisa da tutti i processi che utilizzano # del pragma: http://www.codeproject.com/KB/DLL/data_seg_share.aspx

+0

Sì, spero che possa essere risolto con boost, ma potresti essere più specifico su come creare il segmento di memoria con nome solo nel processo corrente? –

+0

Cosa intendi con "solo processo corrente?" Accessibile da un solo processo? Scrivibile solo da un processo? –

+0

Se creo una memoria condivisa con un ID, sarà accessibile da tutti i processi nel sistema, giusto? Ho bisogno che quella memoria sia accessibile solo dal processo che la crea, con accesso completo in lettura/scrittura –

1

Per uso dal processo corrente, don Non ho bisogno di ideare alcuna funzione o struttura speciale.

si potesse fare anche senza alcuna funzione ma è più piattaforma sicura e cross gentile per definire un insieme di funzioni che forniscono l'accesso ai dati condivisi. E queste funzioni potrebbero essere implementate dalla libreria statica comune.

credo, unica preoccupazione di questa configurazione è che: "Chi sarà proprio i dati?". Deve esistere un solo proprietario dei dati condivisi.

Con questi idea di base, potremmo disegnare l'API in questo modo:

IsSharedDataExist  // check whether of not shared data exist 

CreateSharedData  // create (possibly dynamically) shared data 

DestroySharedData  // destroy shared data 

... various data access API ... 

o Classe C++ con il pattern Singleton sarà appropriata.


UPDATE

ero confuso. Il problema reale può essere definito come "Come implementare una classe Singleton in una libreria statica che sarà collegata a più librerie di caricamento dinamico (verrà utilizzata nello stesso processo) in modo indipendente dalla piattaforma".

penso, idea di base non è molto diverso, ma assicurarsi che il Singleton è il davvero unico è il problema aggiuntivo di questa configurazione.

A tale scopo, si potrebbe impiegare Boost.Interprocess.

#include <boost/config.hpp> 
#include <boost/interprocess/sync/named_mutex.hpp> 
... 
boost::interprocess::named_mutex* singleton_check = 0; 

// in the Create function of the singleton 
try { 
    singleton_check = new boost::interprocess::named_mutex(boost::interprocess::create_only, "name_of_the_mutex"); 
    // if no exception throw, this is the first time execution 
} 
catch (...) 
{ 
} 

Liberare il named_mutex è semplice come delete singleton_check.


UPDATE # 2

Un altro suggerimento.

credo, non dobbiamo inserire i dati condivisi nella libreria statica comune. Se non siamo in grado di garantire dati unici a livello globale, non sono solo i problemi di implementazione dipendenti dalla piattaforma, ma anche lo spreco di memoria e risorse globali.

Se preferite implementazione libreria statica si dovrebbe fare due librerie statiche. Uno per il server/creatore dei dati condivisi, uno per gli utenti di tali dati condivisi. La libreria del server definisce e fornisce l'accesso a Singleton. La libreria client fornisce vari metodi di accesso ai dati.

Questo è effettivamente uguale alla implementazione Singleton, senza librerie statiche.

+0

Il modo in cui avrei dovuto avvicinarmi a questo, era controllare la memoria nominata - se esistesse già, l'avrei accedervi e fare qualsiasi lavoro mi servisse, e se lo fosse non esisteva, quindi l'avrei creato. Lo stesso vale per la deinizzazione: ogni modulo dovrebbe registrarsi, per tracciare il conteggio degli usi e l'ultimo chiuso eseguirà la pulizia. –

+0

Se il suo processo inter-processo è necessario funzionalità speciali fornite nella piattaforma. Ma se è "all'interno del processo corrente", le variabili definite globalmente sono la memoria nominata. – 9dan

+0

Non è possibile condividere le variabili globali in un solo modulo, con copie separate in altri moduli? –

0

Come da MSDN Vedo che ci sono solo due modi per condividere dati tra i moduli

  1. Uso data_seg pragma
  2. Usa memoria condivisa.

Come qualcuno ha sottolineato che il segmento condiviso funziona solo per due istanze della stessa dll, quindi ci rimane solo una scelta per utilizzare la tecnica dei file mappati in memoria.

Problemi correlati