web-dev-qa-db-fra.com

pourquoi pthread provoque une fuite de mémoire

Chaque fois que je crée un pthread, Valgrind génère une fuite de mémoire,

Par exemple le code ci-dessous:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h> 

void *timer1_function (void *eit){
  (void) eit;
    printf("hello world\n");
    pthread_exit(NULL);
}

int main(void){
   pthread_t timer1;
   pthread_create( &timer1, NULL, timer1_function,  NULL);  ///////line13
   int i=0;
   for(i=0;i<2;i++){usleep(1);}
   return 0;
}

sorties valgrind

==1395== HEAP SUMMARY:
==1395==     in use at exit: 136 bytes in 1 blocks
==1395==   total heap usage: 6 allocs, 5 frees, 1,134 bytes allocated
==1395== 
==1395== 136 bytes in 1 blocks are possibly lost in loss record 1 of 1
==1395==    at 0x402A629: calloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==1395==    by 0x4011304: allocate_dtv (dl-tls.c:297)
==1395==    by 0x4011AAB: _dl_allocate_tls (dl-tls.c:461)
==1395==    by 0x4052470: pthread_create@@GLIBC_2.1 (allocatestack.c:571)
==1395==    by 0x8048566: main (test.c:13)
==1395== 
==1395== LEAK SUMMARY:
==1395==    definitely lost: 0 bytes in 0 blocks
==1395==    indirectly lost: 0 bytes in 0 blocks
==1395==      possibly lost: 136 bytes in 1 blocks
==1395==    still reachable: 0 bytes in 0 blocks
==1395==         suppressed: 0 bytes in 0 blocks

pourquoi pthread_create pose-t-il un problème alors que j'utilisais la page de manuel comme référence et comment puis-je résoudre ce problème?

19
Johan Elmander

Un thread est une ressource allouée et vous ne l'avez pas libérée avant de quitter. Vous devriez appeler pthread_join; Cela éliminerait également le besoin de votre boucle de sommeil hackish et incorrecte.

Il est possible que même une fois que vous aurez résolu ce problème, valgrind verra toujours une "fuite", car certaines implémentations de threads POSIX (je suppose que vous utilisez la glibc/NPTL) mettent en cache et réutilisent les ressources de threads au lieu de les libérer complètement. Je ne sais pas si Valgrind contourne cela ou non.

24
R..

Je pense que valgrind analyse l’état de votre programme au moment de sa sortie, probablement avant que le thread ne termine son exécution: deux microsecondes peuvent ne pas suffire pour écrire "Hello, world!\n" sur la console. Ajouter un appel à pthread_join devrait corriger cette fuite:

pthread_join(timer1, NULL);
5
dasblinkenlight

La fuite qui apparaît est liée à la structure DTV (Dynamic Thread Vector) allouée dans le stockage local (tls) du thread enfant.

L’utilisation de pthread_join() dans le thread principal (c’est-à-dire le thread qui a engendré l’enfant) permettra de remédier à la fuite. Pour les cas d’utilisation où pthread_join() n’est pas requis, appeler pthread_detach avec l'enfant pthread_t garantit la libération de la mémoire.

De l'homme pour pthread_detach:

La fonction pthread_detach() marque le thread identifié par le thread Comme étant détaché. Lorsqu'un thread détaché se termine, ses ressources sont Libérées automatiquement vers le système sans qu'il soit nécessaire que Un autre thread se joigne au thread terminé.

1
daemon155

J'ai vu des résultats similaires lorsque je ne parviens pas à appeler pthread_join.

Lorsque j'appelle pthread_join, Valgrind n'indiquera aucune erreur de mémoire ni aucune fuite. J'ai eu un résultat net en utilisant pthread_kill pour voir si le thread existe toujours, puis en appelant join pour nettoyer et libérer les ressources. 

int
stop_worker(worker_t *self)
{
    if (self) {
        // signal the thread to quit
            // (here using a variable and semaphore)
        self->thread_quit=TRUE;
        sem_post(&self->sem);

        // wait for it to stop
        // (could use counter, etc. to limit wait)
        int test=0;
        while (pthread_kill(self->thread,0) == 0) {
            MDEBUG(MD_XF_LOGGER,"waiting for thread to exit...\n",test);
            delay_msec(50);
        }

        // even though thread is finished, need to call join
        // otherwise, it will not release its memory (and valgrind indicates a leak)
        test=pthread_join(self->thread,NULL);
        return 0;           
    }
    return -1;
}
1
klheadley

la fuite de mémoire est due au fait que si le thread est en cours d'exécution sans annulation, la mémoire allouée dynamiquement correspondante n'est pas libérée. Utilisez pthread_cancel () avec pthread_cleanup_Push (CleanupHandler, NULL) et pthread_cleanup_pop (0) pour nettoyer le thread après l'annulation.

0
wrapperm