pthread_cond_wait: erreur de segmentation aléatoire

Mise à jour 3

cemment, j’ai remarqué que mon code provoquait de manière aléatoire des erreurs de segmentation . Mais je pense que mon code est assez simple jusqu’à présent et je ne peux pas comprendre d’où vient cette erreur. Comme cela se produit au hasard, je suppose qu’il existe une sorte de condition de race. Je pense que c’est tout le code qui pourrait être pertinent, dites-moi si vous avez besoin de plus:

namespace thread { pthread_t terminated_thread_id, /* and others */; pthread_mutex_t terminate_thread = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t terminate_thread_signal = PTHREAD_COND_INITIALIZER; int total_thread_count = 0; int termination; // + sembufs inline void* Exit(void* value) { // This must be unlocked after all join-related jobs are done semop(thread::termination, thread::termination_in_process, 2) pthread_mutex_lock(&thread::terminate_thread); thread::terminated_thread_id = pthread_self(); pthread_cond_signal(&thread::terminate_thread_signal); pthread_mutex_unlock(&thread::terminate_thread); pthread_exit(value); return value; } } int main(int argc, const char** argv){ ... pthread_mutex_lock(&thread::terminate_thread); if(0 != pthread_create(&thread::communication_handler_thread_id, NULL, \ CommunicationHandler, NULL)){ global::PrintDebug("pthread_create() failed", __FILE__, __LINE__); } /** 2 more pthread_create()-calls */ do{ thread::terminated_thread_id = pthread_self(); pthread_cond_wait(&thread::terminate_thread_signal, \ &thread::terminate_thread); if(!pthread_equal(thread::terminated_thread_id, pthread_self())){ pthread_join(thread::terminated_thread_id, NULL); ... semop(thread::termination, thread::termination_done, 1) } }while(thread::total_thread_count > 0); pthread_mutex_unlock(&thread::terminate_thread); return 0; } 

Le signal terminate_thread_signal est uniquement émis dans la fonction thread :: Exit () . Cette fonction est également appelée uniquement à la fin de la fonction utilisée pour créer le thread.

Voici ce que le débogueur montre pour la stack d’appels:

 #0 ( 0xb7fe2424 in __kernel_vsyscall() (??:??) #1 0xb7fbdfcf __pthread_cond_wait(cond=0x80539c0, mutex=0x8053998) (pthread_cond_wait.c:153) #2 0x804a094 main(argc=1, argv=0xbffff9c4) (/home/papergay/SeekYourCar/0.2/Server/main.cpp:121) 

Ce que je sais déjà, c’est que si l’erreur se produit, aucun thread n’a encore appelé thread :: Exit (). J’utilise également un espace de noms non nommé avec quelques initialisations (si cela peut être pertinent). J’utilise Code :: Blocks comme IDE et GCC comme compilateur.

pthread_cond_wait() est autorisé à se réveiller faussement, vous devez donc tester à nouveau la condition elle-même après chaque réveil. Cela pourrait être la cause de votre problème – si le thread principal se réveille de manière anarchique avant que thread::terminated_thread_id soit défini, il passera un identifiant de thread invalide à pthread_join() .

Il y a aussi un autre problème dans votre code: rien ne garantit que le thread signalé sera le prochain à se réveiller après le délocking du mutex. Il est donc possible que deux threads appellent successivement thread::Exit() , avec le thread principal. ne fonctionnant pas avant que le second thread sortant ait déverrouillé le mutex. Dans ce cas, vous n’appelerez jamais pthread_join() sur le premier thread.

Quelque chose comme ceci devrait résoudre ces problèmes:

 namespace thread { int terminate_thread_set = 0; pthread_mutex_t terminate_thread = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t terminate_thread_set_cond = PTHREAD_COND_INITIALIZER; pthread_cond_t terminate_thread_unset_cond = PTHREAD_COND_INITIALIZER; /* ... */ inline void Exit(void* value) { pthread_mutex_lock(&thread::terminate_thread); while (thread::terminate_thread_set) pthread_cond_wait(&thread::terminate_thread_unset_cond); thread::terminated_thread_id = pthread_self(); thread::terminate_thread_set = 1; pthread_cond_signal(&thread::terminate_thread_set_cond); pthread_mutex_unlock(&thread::terminate_thread); pthread_exit(value); } } 

et en main :

 pthread_mutex_lock(&thread::terminate_thread); /* ... */ while(thread::total_thread_count > 0) { while (!thread::terminate_thread_set) pthread_cond_wait(&thread::terminate_thread_set_cond, &thread::terminate_thread); thread::terminate_thread_set = 0; pthread_join(thread::terminated_thread_id, NULL); pthread_cond_signal(&thread::terminate_thread_unset_cond); ... } pthread_mutex_unlock(&thread::terminate_thread); 

Cela ne veut pas dire que vous n’avez pas d’autres problèmes, bien sûr.

On dirait que vous déverrouillez votre mutex termin_in_process de votre processus principal – même s’il était verrouillé par un autre thread – ce qui constitue un comportement indéfini. Cela pourrait fonctionner, et cela pourrait ne pas fonctionner.

Une solution pourrait consister à utiliser un tampon FIFO (par exemple std :: queue , ou même simplement std :: vector ) et à y insérer l’identifiant de thread de vos threads terminés dans votre fonction Exit() , puis d’envoyer votre signal et laissez le thread principal parcourir le tampon et y joindre tous les threads.

Si Exit() n’est pas appelé au sharepoint votre erreur de segmentation, cela ne devrait cependant pas être la raison de votre problème, mais vous voudrez peut-être résoudre ce problème.

C’est assez tard, mais j’ai oublié de le poster pour des références futures. Voici comment je l’ai corrigé:

J’ai mis à niveau mon compilateur GCC de la version 4.5.X à la version 4.7.X ainsi que mon kernel de 2.6.X à 3.2.X et corrige quelques erreurs concernant l’instanciation globale d’une classe et d’une variable membre statique en fournissant un constructeur explicite afin de permettre une déclaration globale sans initialisation. Mais je pense que la mise à niveau du compilateur GCC est tout ce qui était nécessaire.

On dirait que l’implémentation de la fonction n’était pas correcte. Ou il y avait des erreurs dans le code du kernel?