Condividi tramite


Come si condividono i dati della DLL con un'applicazione o altre DLL?

Aggiornamento: novembre 2007

Le DLL Win32 sono mappate nello spazio degli indirizzi del processo chiamante. Per impostazione predefinita, ogni processo che utilizza una DLL dispone di una propria istanza di tutte le variabili globali e statiche delle DLL. Se la DLL deve condividere i dati con altre istanze caricate da altre applicazioni, è possibile utilizzare uno degli approcci seguenti.

  • Creare sezioni di dati con nome utilizzando il pragma data_seg.

  • Utilizzare i file mappati alla memoria. Vedere la documentazione relativa alla gestione dei file mappati alla memoria in Win32 in MSDN Library.

Di seguito è riportato un esempio di utilizzo del pragma data_seg.

#pragma data_seg (".myseg")
   int i = 0; 
   char a[32]n = "hello world";
#pragma data_seg()

data_seg può essere utilizzato per creare una nuova sezione con nome, .myseg in questo esempio. Per motivi di chiarezza, è consuetudine chiamare il segmento di dati .shared. È quindi necessario specificare gli attributi di condivisione corretti per questa nuova sezione di dati con nome nel file def o con l'opzione del linker /SECTION:.MYSEC,RWS.

Prima di utilizzare un segmento di dati con nome è bene prendere in considerazione alcune restrizioni.

  • Tutte le variabili in un segmento di dati con nome devono essere inizializzate staticamente. Nell'esempio precedente la variabile i è inizializzata su 0 mentre la variabile a, composta da 32 caratteri, è inizializzata su hello world.

  • Tutte le variabili condivise vengono inserite nella DLL compilata nel segmento di dati specificato. Matrici molto grandi possono generare DLL molto grandi. Questa regola è valida per tutte le variabili globali inizializzate.

  • Non memorizzare mai informazioni specifiche del processo in un segmento di dati condiviso. La maggior parte delle strutture di dati o dei valori Win32, come ad esempio HANDLE, è valida solo all'interno del contesto di un singolo processo.

  • Ciascun processo ottiene il proprio spazio degli indirizzi. È molto importante non memorizzare mai i puntatori in una variabile contenuta in un segmento di dati condiviso. Un puntatore potrebbe essere perfettamente valido in un'applicazione ma non in un'altra.

  • Può accadere che la DLL venga caricata in un diverso indirizzo negli spazi degli indirizzi virtuali di ciascun processo. Non è sicuro avere dei puntatori a funzioni nella DLL o ad altre variabili condivise.

Tenere presente che questi ultimi tre punti si applicano a file mappati alla memoria e a segmenti di dati condivisi.

Contrariamente alle sezioni di dati condivisi, l'inizio dei file mappati alla memoria è noto, il che rappresenta un vantaggio. Gli sviluppatori possono implementare comportamenti tipo puntatore utilizzando l'offset dall'inizio della sezione della memoria condivisa in tutti i dati che si trovano all'interno della memoria condivisa. Per rendere quest'operazione rapida e semplice, si consigliano i puntatori __based. È però importante ricordare che la base, ovvero l'inizio del file mappato alla memoria, potrebbe essere diversa per ciascun processo. Di conseguenza, la variabile in cui è memorizzata la base per i puntatori __based non può trovarsi nella memoria condivisa.

Queste restrizioni hanno delle implicazioni importanti per le classi C++.

  • Le classi con funzioni virtuali contengono sempre dei puntatori a funzioni. Le classi con funzioni virtuali non devono mai essere memorizzate in segmenti di dati condivisi o in file mappati alla memoria. Queste regole sono particolarmente importanti per le classi MFC o per quelle che ereditano da MFC.

  • I membri dati statici sono implementati come l'equivalente delle variabili globali, il che significa che ogni processo avrebbe una propria copia dei membri dati statici di quella classe. Le classi con membri dati statici non devono essere condivise.

  • I requisiti di inizializzazione di un segmento dati condiviso causano un problema particolare per le classi C++. Se in un segmento dati condiviso è presente un'istruzione simile a CTest Counter(0);, l'oggetto Counter verrà inizializzato in ciascun processo al momento del caricamento della DLL, potenzialmente azzerando ogni volta i dati dell'oggetto. I tipi di dati intrinseci inizializzati dal linker al momento della creazione della DLL si comportano invece in modo alquanto diverso.

Considerate queste restrizioni, Microsoft sconsiglia la condivisione degli oggetti C++ fra i processi. In genere, se si desidera utilizzare C++ per condividere i dati tra i processi, occorre scrivere una classe che utilizzi internamente un file mappato alla memoria per la condivisione dei dati, senza condividere le istanze di classe. Sebbene richieda una particolare attenzione, questa classe consente agli sviluppatori di applicazioni di avere il controllo completo sugli effetti collaterali della condivisione dei dati.

Per ulteriori informazioni sulla creazione di sezioni di dati con nome, vedere i seguenti articoli della Knowledge Base all'indirizzo https://support.microsoft.com/?ln=IT:

  • "How to Share Data Between Different Mappings of a DLL" (Q125677).

  • "Specifying Shared and Nonshared Data in a DLL" (Q100634).

  • "Sharing All Data in a DLL" (Q109619).

  • "Memory in Shared Code Sections Is Not Shared Across Terminal Server Sessions" (Q251045)

Vedere anche

Concetti

Domande frequenti relative alle DLL