J'ai une fonction de coureur pthread joignable définie comme ci-dessous:
void *sumOfProducts(void *param)
{
...
pthread_exit(0);
}
Ce thread est censé rejoindre le thread principal.
Chaque fois que j'exécutais mon programme via Valgrind, j'obtenais les fuites suivantes:
LEAK SUMMARY:
definitely lost: 0 bytes in 0 blocks
indirectly lost: 0 bytes in 0 blocks
possibly lost: 0 bytes in 0 blocks
still reachable: 968 bytes in 5 blocks
suppressed: 0 bytes in 0 blocks
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 from 10)
J'ai vérifié la page de manuel pour pthreads qui disait:
The new thread terminates in one of the following ways:
* It calls pthread_exit(3), specifying an exit status value that is
available to another thread in the same process that calls
pthread_join(3).
* It returns from start_routine(). This is equivalent to calling
pthread_exit(3) with the value supplied in the return statement.
* It is canceled (see pthread_cancel(3)).
* Any of the threads in the process calls exit(3), or the main thread
performs a return from main(). This causes the termination of all
threads in the process.
Miraculeusement, lorsque j'ai remplacé pthread_exit () par une instruction return, les fuites ont dispar.
return(NULL);
Ma vraie question est à trois volets:
Le scénario de test minimal suivant présente le comportement que vous décrivez:
#include <pthread.h>
#include <unistd.h>
void *app1(void *x)
{
sleep(1);
pthread_exit(0);
}
int main()
{
pthread_t t1;
pthread_create(&t1, NULL, app1, NULL);
pthread_join(t1, NULL);
return 0;
}
valgrind --leak-check=full --show-reachable=yes
Montre 5 blocs alloués à partir de fonctions appelées par pthread_exit()
qui sont non libérés mais toujours accessibles à la sortie du processus. Si la pthread_exit(0);
est remplacée par return 0;
, Les 5 blocs ne sont pas alloués.
Cependant, si vous testez la création et la jonction d'un grand nombre de threads, vous constaterez que la quantité de mémoire non libérée utilisée à la sortie pas augmente. Ceci, et le fait qu'il soit toujours accessible, indique que vous voyez juste une bizarrerie de l'implémentation de la glibc. Plusieurs fonctions glibc allouent de la mémoire avec malloc()
la première fois qu'elles sont appelées, qu'elles conservent allouées pour le reste de la durée de vie du processus. glibc ne prend pas la peine de libérer cette mémoire à la sortie du processus, car elle sait que le processus est de toute façon détruit - ce serait juste une perte de cycles CPU.
Je ne sais pas si cela vous intéresse toujours, mais je débogue actuellement une situation similaire. Threads qui utilisent pthread_exit
oblige valgrind à signaler les blocs accessibles. La raison semble être assez bien expliquée ici:
https://bugzilla.redhat.com/show_bug.cgi?id=483821
Il semble essentiellement pthread_exit
provoque un dlopen
qui n'est jamais nettoyé explicitement à la fin du processus.
Cela ressemble à appeler exit () (et, apparemment, pthread_exit ()) laisse les variables allouées automatiquement allouées. Vous devez soit retourner ou lancer afin de vous détendre correctement.
Par C++ valgrind fuites possibles sur la chaîne STL :
@Klaim: Je ne vois pas où ce document dit que je me trompe, mais si c'est le cas, alors c'est faux. Pour citer la norme C++ (§18.3/8): "Les objets automatiques ne sont pas détruits suite à l'appel de exit ()." - James McNellis 10 septembre 10 à 19:11
Puisque faire un "return 0" au lieu de "pthread_exit (0)" a semblé résoudre votre problème (et le mien .. merci), je suppose que le comportement est similaire entre les deux.
J'ai l'expérience que valgrind a des difficultés à suivre le stockage alloué pour l'état des threads joignables. (Cela va dans le même sens que l'indique caf.)
Puisqu'il semble que vous renvoyiez toujours une valeur de 0
Je suppose que vous devez peut-être joindre vos discussions du point de vue de l'application? Si c'est le cas, envisagez de les lancer détachés dès le départ, cela évite l'allocation de cette mémoire.
L'inconvénient est que vous avez:
main
. Si vous connaissez le nombre de threads au préalable, un simple pthread_barrier
Alloué statiquement suffirait.main
avec pthread_exit
afin de ne pas tuer les autres threads en cours d'exécution qui ne sont peut-être pas encore terminés.Utilisez-vous réellement C++, par hasard? Pour clarifier - votre fichier source se termine par un .c
extension, et vous la compilez avec gcc
, pas g++
?
Il semble raisonnablement probable que votre fonction alloue des ressources que vous prévoyez de nettoyer automatiquement au retour de la fonction. Objets C++ locaux comme std::vector
ou std::string
faites cela, et leurs destructeurs ne seront probablement pas exécutés si vous appelez pthread_exit
, mais serait nettoyé si vous revenez.
Ma préférence est d'éviter les API de bas niveau telles que pthread_exit
, et toujours simplement revenir de la fonction thread, si possible. Ils sont équivalents, sauf que pthread_exit
est une construction de contrôle de flux de facto qui contourne le langage que vous utilisez, mais pas return
.