2010-09-15 4 views
4

J'ai un programme que je lie avec de nombreuses bibliothèques. J'ai couru mon application sur profiler et ai découvert que la plupart du temps est passée dans l'état "d'attente" après quelques demandes de réseau. Ces demandes sont l'effet de mon code appelant sleeping_function() de la bibliothèque externe. J'appelle cette fonction dans une boucle qui s'exécute plusieurs fois de sorte que tous les temps d'attente totalisent des quantités énormes.Comment lier une bibliothèque non thread-safe pour que chaque thread ait ses propres variables globales?

Comme je ne peux pas modifier le sleeping_function() Je veux démarrer quelques threads pour exécuter quelques itérations de ma boucle en parallèle. Le problème est que cette fonction utilise en interne certaines variables globales.

Existe-t-il un moyen de dire à l'éditeur de liens sur SunOS que je veux lier des bibliothèques spécifiques d'une manière qui va placer toutes les variables d'entre eux dans le stockage local de thread?

+1

Belle question. S'il vous plaît veuillez également les solutions Linux/Windows. –

Répondre

0

Je ne pense pas que vous serez en mesure d'atteindre cet objectif avec juste l'éditeur de liens, mais vous pourriez être en mesure d'obtenir quelque chose de travailler avec un code en C.

Le problème est qu'un appel à charger un La bibliothèque déjà chargée renverra une référence à l'instance déjà chargée au lieu de charger une nouvelle copie. Un rapide coup d'oeil à la documentation pour dlopen et LoadLibrary semble confirmer qu'il n'y a aucun moyen de charger la même bibliothèque plus d'une fois, du moins pas si vous voulez que l'image soit préparée pour l'exécution. Une façon de contourner ce problème serait d'empêcher le système d'exploitation de savoir que c'est la même bibliothèque. Pour ce faire, vous pouvez faire une copie du fichier.

Certains pseudo-code, il suffit de remplacer les appels à sleeping_function avec des appels à call_sleeping_function_thread_safe:

char *shared_lib_name 

void sleeping_function_thread_init(char *lib_name); 

void call_sleeping_function_thread_safe() 
{ 
    void *lib_handle; 
    pthread_t pthread; 
    new_file_name = make_copy_of_file(shared_lib_name); 

    pthread_create(&pthread, NULL, sleeping_function_thread_init, new_file_name); 
} 

void sleeping_function_thread_init(char *lib_name) 
{ 
    void *lib_handle; 
    void (*)() sleeping_function; 

    lib_handle = dlopen(lib_name, RTLD_LOCAL); 
    sleeping_function = dlsym(lib_handle, "sleeping_function") 
    while (...) 
    sleeping_function; 
    dlclose(lib_handle); 
    delete_file(lib_name);  
} 

Pour les fenêtres dlopen devient LoadLibrary et dlsym devient GetProcAddress etc ... mais l'idée de base fonctionne encore.

+0

Cela ne fonctionnera pas car je dois lier le programme entier statiquement. – elmo

1

En général, c'est une mauvaise idée. Les données globales ne sont pas le seul problème qui peut empêcher une bibliothèque non thread-safe de s'exécuter dans un environnement multithread. Par exemple, que se passe-t-il si la bibliothèque possède une variable globale qui pointe vers un fichier mappé en mémoire qu'elle mappe toujours en une seule adresse codée en dur. Dans ce cas, avec votre technique, vous auriez une variable globale par thread, mais ils pointeraient tous vers le même emplacement de mémoire, qui serait saccagé par un accès multi-thread.

+0

Je suis d'accord, mais ce n'est pas le cas. J'ai accès aux sources de la bibliothèque, mais je ne peux rien changer et je dois lier avec l'objet de bibliothèque statique donné. – elmo

+0

C'était un exemple. Êtes-vous sûr que la bibliothèque ne fait aucune supposition qu'elle s'exécute dans un seul thread? Pas même des suppositions implicites? –

Questions connexes