2012-07-26 29 views
5

Tengo una aplicación multiproceso. Declaro una clase con un miembro estático en una biblioteca compartida.dos instancias de un miembro estático, ¿cómo podría ser eso?

Al imprimir la dirección del miembro de diferentes subprocesos de diferentes bibliotecas se muestran resultados diferentes.

// declaración

template <class OBJECT> 
struct Container 
{ 
    static int m_member; 
}; 

template <class OBJECT> 
int Container<OBJECT>::m_member; 

// imprimiendo

cout << (void*) &Container<int>::m_member << endl; 

¿Cómo puede ser?

+0

Cuando dice diferentes hilos de diferentes bibliotecas, ¿quiere decir que tiene un proceso que tiene varios hilos que acceden al miembro? Cuando recuerdo correctamente, escuché que las bibliotecas compartidas se instancian por proceso, por lo que cada proceso tiene su propia versión (para no interferir con otros procesos). – Nobody

+1

¿Cómo se vincula la "biblioteca compartida"? –

+0

Es un proceso con varios hilos. El miembro está definido en el archivo de encabezado (en mi código real, el contenedor está modelado), pero estoy bastante seguro de que este no es el problema. – Ezra

Respuesta

4

Si tiene bibliotecas diferentes, (supongo que diferentes bibliotecas dinámicas), entonces puede tener alguna duplicación de código y variables estáticas.

Los detalles exactos dependerán de la tecnología de biblioteca dinámica particular que esté utilizando. Yo diría que, por ejemplo, en las DLL de Windows tendrá código duplicado y variables, pero en las SO de Linux no lo hará.

De todos modos, debe proporcionar más detalles sobre el sistema operativo y el diseño de su proyecto.

ACTUALIZACIÓN: ¡Ahh, pero su clase es una plantilla! Las instancias de plantillas en una biblioteca compartida son una bestia extraña. Para asegurarse de que solo se utiliza una copia de su clase en todo el proceso, debe crear una instancia explícita de la plantilla y asegurarse de que esta instanciación se exporte en el SO y que se utilice desde el código del cliente. Los detalles varían con el compilador, pero se puede comprobar cómo se realiza la std::string, por ejemplo:

En el archivo de cabecera:

namespace std 
{ 
    extern template class basic_string<wchar_t>; 
} 

En la fuente de la biblioteca:

namespace std 
{ 
    template class basic_string<wchar_t>; 
} 

Naturalmente, necesita saber de antemano qué ejemplos se necesitarán de su plantilla. Obviamente, el SO no puede exportar una instanciación que utiliza un tipo del que no sabe nada.

ACTUALIZACIÓN: Ahh, pero hay dos bibliotecas diferentes instantating la plantilla ... entonces si ambas bibliotecas definen la creación de instancias explícita como extern la magia compartido ELF debe fusionar ambas instancias en una sola.

YET OTRA ACTUALIZACIÓN: Después de jugar con plantillas y objetos compartidos, por lo general solo funciona. Supongo que ahora está compilando las bibliotecas con -fvisibility=hidden o similar. Si ese es el caso, sería suficiente sólo para escribir:

template <class OBJECT> 
struct __attribute__((visibility("default"))) Container 
{ 
    static int m_member; 
}; 

Para hacer las especializaciones de la plantilla para entrar en la tabla de símbolos dinámico, y por lo tanto evitar la duplicación.

+0

Yo uso linux CentOS, por lo tanto SO. Por lo que sé, solo debería haber una instancia de Container :: m_member. – Ezra

+0

+1. Sin embargo, he intentado con sus sugerencias y sigo teniendo dos instancias. Si eso pudiera dar una pista: las direcciones que estoy viendo son de diferentes longitudes: 0x61bdb0, 0x2aaaab92d5b0. Mi máquina es de 64 bits. – Ezra

+0

@Ezra: He hecho un ejemplo y pude obtener los dos resultados (misma dirección o diferentes direcciones) simplemente jugando con las opciones de visibilidad. Deberías publicar un código compilable y los comandos del compilador que reproducen tu problema. – rodrigo

Cuestiones relacionadas