Je ne sais pas si cela vous intéresse toujours, mais je suis actuellement en train de déboguer une situation similaire. Threads utilisant 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
Essentiellement, il semble pthread_exit
provoque un dlopen
qui n'est jamais nettoyé explicitement lorsque le processus se termine.
Le cas 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 n'est pas libéré mais toujours accessible à la sortie du processus. Si le pthread_exit(0);
est remplacé 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 ne le fait pas augmenter. Ceci, et le fait qu'il soit toujours accessible, indique que vous ne voyez qu'une bizarrerie de l'implémentation de la glibc. Plusieurs fonctions de la glibc allouent de la mémoire avec malloc()
la première fois qu'ils sont appelés, qu'ils gardent alloués pour le reste de la durée de vie du processus. La 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.
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 vous attendez à nettoyer automatiquement lors du retour de la fonction. Objets C++ locaux comme std::vector
ou std::string
faites ceci, et leurs destructeurs ne seront probablement pas exécutés si vous appelez pthread_exit
, mais serait nettoyé si vous venez de revenir.
Ma préférence est d'éviter les API de bas niveau telles que pthread_exit
, et revenez toujours 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 return
pas.