2010-12-31 10 views
6

Estoy teniendo un problema con Valgrind que indica que hay algo de memoria posible perdida:pthread_create seguido por pthread_detach todavía provoca error posiblemente perdido en Valgrind

==23205== 544 bytes in 2 blocks are possibly lost in loss record 156 of 265 
==23205== at 0x6022879: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==23205== by 0x540E209: allocate_dtv (in /lib/ld-2.12.1.so) 
==23205== by 0x540E91D: _dl_allocate_tls (in /lib/ld-2.12.1.so) 
==23205== by 0x623068D: [email protected]@GLIBC_2.2.5 (in /lib/libpthread-2.12.1.so) 
==23205== by 0x758D66: MTPCreateThreadPool (MTP.c:290) 
==23205== by 0x405787: main (MServer.c:317) 

El código que crea estos hilos (MTPCreateThreadPool) básicamente se un índice en un bloque de espera pthread_t slots, y crea un hilo con eso. TI se convierte en un puntero a una estructura que tiene un índice de subproceso y un pthread_t. (Simplificado/desinfectado):

for (tindex = 0; tindex < NumThreads; tindex++) 
    { 
    int rc; 
    TI = &TP->ThreadInfo[tindex]; 
    TI->ThreadID = tindex; 

    rc = pthread_create(&TI->ThreadHandle,NULL,MTPHandleRequestsLoop,TI); 
    /* check for non-success that I've omitted */ 
    pthread_detach(&TI->ThreadHandle); 
    } 

entonces tenemos un MTPDestroyThreadPool función que recorre todos los temas que hemos creado y les cancela (ya que el MTPHandleRequestsLoop no sale).

for (tindex = 0; tindex < NumThreads; tindex++) 
    { 
    pthread_cancel(TP->ThreadInfo[tindex].ThreadHandle); 
    } 

He leído en otro lugar (incluyendo otras preguntas aquí en SO) que separar un hilo de forma explícita podría evitar este error, posiblemente perdido, pero está claro que no lo es. ¿Alguna idea?

Respuesta

4

Una razón podría ser que pthread_cancel en realidad no cancela el hilo, no está garantizado. La cancelación del hilo es asíncrona; pthread_cancel regresa inmediatamente, pero la cancelación puede diferirse hasta el siguiente punto de cancelación. En ese caso, los hilos aún pueden estar presentes cuando Valgrind recabe estadísticas.

+0

También era lo que estaba a punto de sugerir, y posiblemente probar el valor de retorno de 'pthread_cancel' –

+0

Así que si cualquiera de los hilos (potencialmente todos) están bloqueando en un semáforo, la cancelación volverá inmediatamente, pero ya que ' re bloqueado, ¿es muy probable que el proceso del servidor principal salga antes de que realmente se cancele? – alesplin

+0

sem_wait es un punto de cancelación (http://compute.cnr.berkeley.edu/cgi-bin/man-cgi?cancellation+5), por lo que si el hilo es cancelable, la espera debería cancelarse de inmediato. Un hilo que gira en un ciclo infinito es un mejor candidato. Sin embargo, primero debe establecer si eso es lo que sucede, es decir, si los hilos se cancelan o no. –

8

La implementación de los subprocesos de glibc filtra intencionalmente la memoria. Mantiene la memoria asignada a un contexto de subproceso en caché para reutilizar la próxima vez que se crea un subproceso. Hice algunos benchmarking versus una implementación sin el almacenamiento en caché, y parece que el almacenamiento en caché afeita el 50% del tiempo óptimo para pthread_create, pero ralentiza drásticamente pthread_join, para una pérdida neta. Por supuesto, sigue siendo una ganancia (pequeña) si lo que te importa es la latencia de creación de hilo y no el rendimiento.

También tenga en cuenta que es muy difícil para un subproceso separado desasignar su contexto, incluso si lo desea. Con un hilo que se puede unir, el hilo que llama a pthread_join puede desasignar el contexto, pero un hilo separado debería poder operar sin pila durante el intervalo entre la desasignación de su contexto y la terminación de sí mismo. Esto solo se puede lograr escribiendo ese pequeño fragmento de código en puro asm.

¿Se pregunta cómo se devuelven los contextos de los subprocesos separados al caché sin una condición de raza similar? Linux tiene una función para poner a cero un int en una dirección particular (registrada por la biblioteca de hilos del espacio de usuario) cuando finaliza el hilo. Por lo tanto, el hilo puede agregar su propio contexto a la memoria caché de forma segura, ya que hasta que finalice, otros hilos verán un valor distinto de cero (generalmente su id. De hilo) en esta dirección e interpretarán eso para indicar que el contexto todavía está en uso.

0

Crear un hilo que se pueda unir para separarlo inmediatamente no tiene mucho sentido para mí. Esto no crea nada más que sobrecarga para el sistema.

Comenzaría los hilos desprendidos desde el principio, de todos modos tiene su estructura de datos ThreadInfo compartida para controlar sus hilos.

También tendría una bandera o algo así en su argumento por hilo ThreadInfo que le dice al hilo que se cierre de forma controlada.

+0

Buen punto. No escribí el código en cuestión, solo busco la causa (y la cura) del mensaje "posiblemente perdido" en Valgrind, pero también puedo solucionarlo mientras estoy en ello. – alesplin

Cuestiones relacionadas