2009-11-17 23 views
12

Estoy ejecutando Linux, y me gustaría poder hacer llamadas de función paralelas en una biblioteca compartida (.so) que desafortunadamente no es segura (supongo que tiene estructuras de datos globales).Cargar copias múltiples de una biblioteca compartida

Por motivos de rendimiento, no quiero simplemente envolver las llamadas de función en un mutex.

Lo que me gustaría hacer es generar, decir 4 hilos, y también cargar 4 copias de la misma biblioteca en la memoria de proceso. Cada hilo hace que la función llame a su propia copia de la biblioteca.

Desafortunadamente, dlopen no me permite cargar más de una instancia de cualquier biblioteca.

¿Alguien sabe de algún método que me permita cargar la biblioteca más de una vez? (Además de hacer 4 copias del archivo .so, cada una con un nombre diferente)

+0

Para aquellos que necesitan un ejemplo, implementaron la comparación [aquí] (https://github.com/ikoryakovskiy/not_threadsafe_test). – Ivan

Respuesta

6

En lugar de utilizar subprocesos, puede utilizar procesos múltiples, cada uno haciendo parte del trabajo. Esto es muy común en * nix, y generalmente es más fácil de codificar.

+2

No sé si es más fácil codificar. Claro, es ligeramente más fácil llamar 'fork()' luego es lanzar un hilo. Pero si necesita comunicarse entre procesos o compartir datos entre procesos, entonces entra al mundo de IPC (memoria compartida, tuberías, etc.), que es posiblemente más complicado de codificar. –

+2

Para empezar, es más fácil usar su biblioteca que no es segura para subprocesos. :) Me resulta más fácil codificar porque es más fácil evitar interbloqueos y problemas relacionados, pero, sí, también tienen sus versiones en IPC. –

+1

@Charles: dado el objetivo del OP, ir a múltiples procesos es probablemente su opción menos dolorosa. –

1

Parece una mala idea. Eso no es más posible con las bibliotecas compartidas que con las estáticas.

Probablemente podría usar dlopen() con indicador RTLD_LOCAL para que las llamadas subsiguientes a dlopen no vean que ya está cargado y haga que funcione como lo desee ... pero aún parece una mala idea de diseño. Si tiene problemas de rendimiento, sería mejor evitar llenar la memoria con varias copias de la misma biblioteca.

Sugeriría usar varios procesos o seguir el método mutex, probablemente sea más eficiente.

Como trabajas en Linux, también puede haber otros enfoques si puedes acceder al código fuente de la biblioteca, como cambiar el nombre de sus símbolos para tener tantas instancias separadas como necesites ... Bueno, una vez que obtienes la fuente, puede haber ser de otras maneras, como hacer que la biblioteca sea segura.

0

¿Qué biblioteca es? ¿Es algo grande? Me pregunto si no podría arreglar la biblioteca para que sea segura en cuanto a los hilos, luego construya su código usando la versión segura de la biblioteca. Depende del tamaño de la biblioteca, y de lo que no funciona, pero si pudieras arreglar la biblioteca, podrías construir tu aplicación de la manera que quieras, así como ayudar a todos los demás.

+1

¿Por qué lo redactas como si exponer una API que no es segura de roscas es algo incorrecto y que requiere una solución? Hay compensaciones tanto para proporcionar garantías de seguridad de hilo, y no. – ulidtko

+0

@ulidtko: la pregunta original es sobre el uso de una API que no sea segura para los hilos de forma que la falta de seguridad de los hilos rompa las cosas. Para los propósitos del cartel original, la biblioteca está rota. Obviamente, no hay ningún problema con las API que no son de rosca, pero para el OP, las correcciones deben realizarse antes de que la biblioteca sea utilizable. Es una cosa de contexto. –

+0

@ulidtko - Además, no sabemos POR QUÉ la biblioteca no es segura para los hilos. Hay muchos y muy buenos motivos para que el código no sea seguro (por ejemplo, los contenedores STL no son seguros), pero también hay muchas menos razones buenas (por ejemplo, el viejo Strtok C usa un puntero interno estático, que quizás tenía sentido en ese momento, pero se ve bastante estúpido desde el punto de vista de hoy). –

7

Usted puede carga de múltiples copias independientes de la biblioteca de la siguiente manera:

#define _GNU_SOURCE 
#include <dlfcn.h> 
... 
void *handle = dlmopen(LM_ID_NEWLM, "/path/to/library.so", RTLD_NOW); 

Más información here.

+0

¿Alguna idea sobre nosotros los usuarios pobres de windows? Sin embargo, esto es muy útil para Linux. – ibell

+0

Esto también funciona en Windows con LoadLibrary y GetProcAddress. Creo que necesita tener varias copias físicas de la DLL, pero funciona bien. –

+0

¡Gracias! Esto te permite hacer algo alocado como envolver una biblioteca de C no segura para subprocesos en una clase de C++. El operador new() de la clase carga la biblioteca con LM_ID_NEWLM y luego usa dlsym() para rellenar los punteros de funciones de la biblioteca como campos de la clase. Úselo como una clase de C++ como lo haría normalmente. Es un truco malicioso, pero funciona cuando no quieres refacturar 10.000 líneas de código de alguien que pertenece a las profundidades del infierno por usar el estado compartido estático. – AdamIerymenko

Cuestiones relacionadas