¿Cómo puedo compartir datos del archivo DLL con una aplicación o con otros archivos DLL?

Actualización: noviembre 2007

Los archivos DLL para Win32 se asignan al espacio de direcciones del proceso de llamada. De forma predeterminada, los procesos que utilizan un archivo DLL tienen su propia instancia de todas las variables globales y estáticas del archivo DLL. Si el archivo DLL necesita compartir datos con otras instancias del mismo cargadas por otras aplicaciones, puede hacerlo de alguna de las siguientes maneras:

  • Con la creación de secciones de datos con nombre mediante la instrucción pragma data_seg.

  • Mediante archivos asignados a la memoria. Vea la documentación "Managing Memory-Mapped Files in Win32" en la Biblioteca MSDN

Éste es un ejemplo de pragma data_seg:

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

Se puede utilizar data_seg para crear un nueva sección con nombre (.myseg en este ejemplo). El uso más normal consiste en llamar .shared al segmento de datos para mayor claridad. Después, deberá especificar los atributos de uso compartido correctos para esta nueva sección de datos con nombre en el archivo .def o con la opción del vinculador /SECTION:.MYSEC,RWS.

Existen restricciones que hay que considerar antes de utilizar un segmento de datos compartidos:

  • Todas las variables de un segmento de datos compartidos se deben inicializar estáticamente. En el ejemplo anterior, i se inicializa a 0 y a se inicializa con la cadena de 32 caracteres "hello world".

  • Todas las variables compartidas se sitúan en el archivo DLL compilado en el segmento de datos especificado. Las matrices muy grandes pueden dar como resultado archivos DLL de gran tamaño. Esto ocurre con todas las variables globales inicializadas.

  • No almacene nunca información específica del proceso en un segmento de datos compartidos. La mayoría de las estructuras de datos o valores (como HANDLE) de Win32 son válidas realmente sólo dentro del contexto de un único proceso.

  • Cada proceso obtendrá un espacio de direcciones propio. Es muy importante que los punteros no se almacenen en una variable de un segmento de datos compartidos. Un puntero puede ser válido en una aplicación pero no en otra.

  • Es posible que el propio archivo DLL pudiera cargarse en una dirección diferente de los espacios de direcciones virtuales de cada proceso. No es seguro tener punteros a funciones en el archivo DLL o a otras variables compartidas.

Observe que estos tres últimos puntos se aplican sólo a los archivos asignados a la memoria y a los segmentos de datos compartidos.

Los archivos asignados a la memoria tienen una ventaja con respecto a las secciones de datos compartidos, y es que se conoce el inicio del archivo asignado a la memoria. Los programadores pueden implementar un comportamiento similar a un puntero mediante un "desplazamiento desde el inicio de la sección de memoria compartida" en todos los datos situados dentro de la memoria compartida. Se recomienda la utilización de punteros __based por cuestiones de velocidad y facilidad. Sin embargo, es importante recordar que la base (o el inicio del archivo asignado a la memoria) podría ser diferente para cada proceso, por lo que la variable que almacene la base para los punteros __based no puede estar a su vez en la memoria compartida.

Estas restricciones tienen importantes implicaciones en las clases de C++.

  • Las clases con funciones virtuales siempre contienen punteros de funciones. Las clases con funciones virtuales no deberían almacenarse en segmentos de datos compartidos ni en archivos asignados a la memoria. Esto es particularmente importante para las clases de MFC o para las clases que heredan de MFC.

  • Los miembros de datos estáticos se implementan como las variables globales. Esto significa que cada proceso tendría su propia copia de los miembros de datos estáticos de la clase. Las clases con miembros de datos estáticos no deberían compartirse.

  • El requisito de inicialización de un segmento de datos compartidos crea un problema concreto para las clases de C++. Si tiene algo similar a CTest Counter(0); en un segmento de datos compartidos, el objeto Counter se inicializará en cada proceso mientras se carga el archivo DLL, restableciendo potencialmente a cero los datos del objeto cada vez. Esto es muy diferente a los tipos de datos intrínsecos que inicializa el vinculador cuando crea el archivo DLL.

Debido a estas restricciones, Microsoft recomienda no compartir objetos de C++ entre procesos. En general, si desea utilizar C++ para compartir datos entre procesos, cree una clase que utilice internamente un archivo asignado a la memoria para compartir datos, pero no comparta las propias instancias de la clase. Esto puede requerir un cuidado especial a la hora de programar esta clase, pero permite que los desarrolladores de la aplicación controlen totalmente los efectos del uso compartido de datos.

Para obtener más información sobre la creación de secciones de datos con nombre, vea los siguientes artículos de Knowledge Base en https://support.microsoft.com:

  • "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)

Vea también

Conceptos

Preguntas más frecuentes sobre archivos DLL