pthread_join - ¿Por qué pthread provoca una pérdida de memoria
threads c++ (5)
Cada vez que creo un pthread, valgrind genera una pérdida de memoria,
Por ejemplo el siguiente código:
#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;
}
salidas 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
¿Por qué pthread_create causa un problema aunque estaba usando la página del manual como referencia y cómo puedo solucionarlo?
Creo que valgrind
analiza el estado de su programa en el momento en que sale, lo cual es probable antes de que el subproceso finalice su ejecución: dos microsegundos pueden no ser suficientes para escribir "Hello, world!/n"
a la consola. Agregar una llamada a pthread_join
debería solucionar esta fuga:
pthread_join(timer1, NULL);
He visto resultados similares cuando no pude llamar pthread_join.
Cuando llamo a pthread_join, Valgrind indicará que no hay errores de memoria o pérdidas. He tenido un resultado limpio utilizando pthread_kill para ver si el hilo aún existe, y luego llamar a join para limpiar y liberar recursos.
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;
}
La fuga que se muestra está relacionada con la estructura DTV (Dynamic Thread Vector) que se asigna en el almacenamiento local del subproceso secundario (tls).
El uso de pthread_join()
en el subproceso principal (es decir, el subproceso que engendró al niño) asegurará la reparación de la fuga. Para los casos de uso donde no se requiere la llamada pthread_join()
, llamar a pthread_detach
con el hijo pthread_t garantiza que se libere la memoria.
Del hombre para pthread_detach
:
La función
pthread_detach()
marca el hilo identificado por hilo como separado. Cuando un hilo separado termina, sus recursos se liberan automáticamente al sistema sin la necesidad de que otro hilo se una con el hilo terminado.
Un subproceso es un recurso asignado y no lo liberó antes de salir. Deberías llamar a pthread_join
; Esto también eliminaría la necesidad de tu piratería y el bucle de sueño incorrecto.
Es posible que incluso una vez que solucione esto, valgrind siga viendo una "fuga", ya que algunas implementaciones de subprocesos POSIX (supongo que está usando glibc / NPTL) almacenan en caché y reutilizan los recursos de subprocesos en lugar de liberarlos por completo. No estoy seguro de si valgrind funciona alrededor de esto o no.
la pérdida de memoria es el resultado del hecho de que si el subproceso se deja ejecutando sin cancelación, entonces la memoria asignada dinámicamente correspondiente no se libera. Use pthread_cancel () junto con pthread_cleanup_push (CleanupHandler, NULL) y pthread_cleanup_pop (0) para realizar la limpieza del hilo después de la cancelación.