Vous n'êtes pas identifié(e).
- Contributions : Récentes | Sans réponse
#1 22/12/2010 20:35:11
- djeauh
- Membre
Fonction postgres problème multithreading avec getaddrinfo
Bonsoir,
Voici mon problème: j'ai une fonction postgresql qui créé X thread de travail, chaque thread commençant par résoudre un nom d'hote avant de pouvoir continuer à travailler. (Voir exemple de code à la fin de ce post.). Le soucis est que postmaster plante de manière régulière au niveau de cette fameuse résolution de noms. Le seul moyen de ne plus faire planter l'appel à la fonction est de protéger par un mutex l'appel à la fonction getaddrinfo.
Mais voilà d'après le man pages de getaddrinfo cette fonction est réentrante! De plus si je prends les fonctions "working_thread" (en chageant elog par printf bien sur!) et "debug_func" du code ci dessous, et que je les compile dans une application, tout fonctionne correctement!!
En générant les coredumps et en les chargeant dans gdb, j'ai systématiquement la pile suivante:
(gdb) bt
#0 0x00007f09efe9cb66 in fgets_unlocked () from /lib/libc.so.6
#1 0x00007f09ed97a577 in ?? () from /lib/libnss_files.so.2
#2 0x00007f09ed97ab78 in _nss_files_gethostbyname2_r () from /lib/libnss_files.so.2
#3 0x00007f09efee752b in ?? () from /lib/libc.so.6
#4 0x00007f09efee8ff9 in getaddrinfo () from /lib/libc.so.6
#5 0x00007f09ed74157c in working_thread (param=0x0) at entry_point.cpp:266
#6 0x00007f09ebf6dfc7 in start_thread () from /lib/libpthread.so.0
#7 0x00007f09efefd64d in clone () from /lib/libc.so.6
#8 0x0000000000000000 in ?? ()
et voici ce que j'obtiens sur stderr:
*** glibc detected *** XXXXX: XXXXX XXXXX XXX.XXX.XXX.XXX(40360) SELECT: double free or corruption (!prev): 0x000000000189ad50 ***
======= Backtrace: =========
/lib/libc.so.6[0x7f09efea19a8]
/lib/libc.so.6(cfree+0x76)[0x7f09efea3ab6]
/lib/libc.so.6(fclose+0x151)[0x7f09efe91e01]
/lib/libnss_files.so.2(_nss_files_gethostbyname2_r+0x17e)[0x7f09ed97abfe]
/lib/libc.so.6[0x7f09efee76cb]
/lib/libc.so.6(getaddrinfo+0x1d9)[0x7f09efee8ff9]
/usr/local/pgsql/lib/XXX/XXX.so(_Z14working_threadPv+0x66)[0x7f09ed74157c]
/lib/libpthread.so.0[0x7f09ebf6dfc7]
/lib/libc.so.6(clone+0x6d)[0x7f09efefd64d]
Note: j'ai aussi essayé gethostbyname_r et j'ai les même soucis .
Auriez-vous des pistes à me donner SVP? Merci d'avance!
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
#include <pthread.h>
#include <iostream>
#include <list>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC
;
#endif
PG_FUNCTION_INFO_V1(test)
;
Datum test( PG_FUNCTION_ARGS );
#ifdef __cplusplus
}
#endif
void *working_thread( void *param ) {
struct addrinfo *address_info = NULL;
int resolving_result = 0; //
elog(INFO, "Démarrage thread %lu", pthread_self());
resolving_result = getaddrinfo( "www.example.com", "80", NULL, &address_info );
freeaddrinfo( address_info );
elog(INFO, "Résultat dans le thread %lu : %d", pthread_self(), resolving_result);
sleep( 2 ); //On simule un gros traitement
elog(INFO, "Fin thread %lu", pthread_self());
return (NULL);
}
void debug_func() {
//Principe: on veut fait "max_calls" appels à la fonction working_thread en parallèle,
// en n'autorisant que "max_threads" threads concurrent
//Nos définitions:
const int max_threads = 5;
const int max_calls = 100;
//Element en cours de traitement
int current_idx = 0;
//Une liste de threads + un itérateur pour la parcourir
std::list<pthread_t> threads;
std::list<pthread_t>::iterator it;
//Identifiant de thread temporaire
pthread_t tmp;
//Un booléen qui servira dans notre boucle
bool found = false;
do {
if( threads.size() < max_threads ) {
pthread_create( &tmp, NULL, working_thread, NULL );
threads.push_back( tmp );
++current_idx;
} else {
//Les "max_calls" threads sont en cours d'éxécution, on attends qu'il y en ait un qui se libère
for( it = threads.begin(); it != threads.end(); ++it ) {
if( pthread_tryjoin_np( *it, NULL ) == 0 ) {
//Le thread est terminé: on l'enlève de notre liste
threads.erase( it );
found = true;
break;
}
}
//Si aucun "slot" n'est libre, on attends 1 seconde
if( !found ) {
sleep( 1 );
}
}
} while( current_idx < max_calls ); //On créé les threads tant qu'on n'a pas fini nos traitements
//On attends les derniers threads
for( it = threads.begin(); it != threads.end(); ++it ) {
pthread_join( *it, NULL );
}
}
Datum test( PG_FUNCTION_ARGS ) {
debug_func();
PG_RETURN_NULL();
}
Hors ligne
#2 23/12/2010 11:45:38
- Marc Cousin
- Membre
Re : Fonction postgres problème multithreading avec getaddrinfo
Je ne suis pas vraiment sûr qu'on puisse écrire du code multithread dans une procédure PL, tout simplement. Cela m'étonnerait que le code du backend (le processus serveur) lui-même soit réentrant. elog, par exemple, ne l'est probablement pas. Il y a aussi des algorithmes de gestion de la mémoire, par exemple, qui ne le sont probablement pas.
Bref, je n'ai pas trouvé de trace de quelqu'un exécutant du code multithreadé dans une procédure stockée.
Marc.
Hors ligne
#3 23/12/2010 12:02:35
- djeauh
- Membre
Re : Fonction postgres problème multithreading avec getaddrinfo
Bonjour et merci de votre réponse. Je vais essayer de faire autrement. Je vous souhaite de bonnes fêtes de fin d'année!
Hors ligne