2011-10-31 21 views
20

Creo un hilo y lo pongo en un bucle infinito. Consigo pérdidas de memoria cuando se comprueba el código con valgrind. Aquí está mi código:¿Cómo puedo eliminar un pthread que está en un bucle infinito, desde fuera de ese bucle?

#include <pthread.h> 
#include <time.h> 

void thread_do(void){ 
    while(1){} 
} 

int main(){ 
    pthread_t th; 
    pthread_create(&th, NULL, (void *)thread_do, NULL); 

    sleep(2); 
    /* I want to kill thread here */ 
    sleep(2); 
    return 0; 
} 

Así que se crea un hilo en main y solo ejecuta thread_do() todo el tiempo. ¿Hay una manera de acabar con él desde el interior principal después de 2 segundos? He intentado tanto pthread_detach(th) y pthread_cancel(th) pero todavía me fugas.

+3

pthreads Cancelación significa que el hilo no tiene ninguna oportunidad de limpiar cualquier memoria asignó. –

+2

Ok, resolví esto simplemente con un 'keepalive = 1' global. Luego cambié el 'while (1)' a 'while (keepalive)'. Para matar el hilo ahora solo tengo que cambiar el valor de la variable keepalive a 0 y voila! – Pithikos

Respuesta

32

Como @sarnold señaló, por defecto el hilo no se puede cancelar con pthread_cancel() sin llamar a cualquiera de las funciones que son puntos de cancelación ... pero esto puede cambiarse utilizando pthread_setcanceltype() para establecer el tipo de cancelación de la secuencia en asíncrona en lugar de diferida. Para hacer eso, agregaría algo como pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); cerca del inicio de su función de hilo, antes de comenzar el ciclo. A continuación, podrá finalizar el hilo llamando al pthread_cancel(th) desde main().

Tenga en cuenta, sin embargo, que las discusiones cancelación de esta manera (ya sea asíncrona o no) no limpiar los recursos asignados en la función de hilo (como se ha señalado por Kevin en un comentario). Con el fin de hacer esto limpiamente, es posible:

  • Asegúrese de que el hilo no hace nada tiene que limpiar antes de la salida (por ejemplo, utilizando malloc() asignar un búfer)
  • Asegúrese de que tiene alguna forma de limpieza después de la rosca en otro lugar, después de que el hilo sale
  • pthread_cleanup_push() uso y pthread_cleanup_pop() a agregar controladores de limpieza para limpiar los recursos cuando el hilo se cancela. Tenga en cuenta que esto sigue siendo riesgoso si el tipo de cancelación es asincrónico, ya que el hilo podría cancelarse entre la asignación de un recurso y la adición del controlador de limpieza.
  • Evitar el uso de pthread_cancel() y tienen el hilo comprobar alguna condición para determinar cuándo terminar (que se comprueba en los bucles de larga duración). Dado que su hilo luego verifica la finalización en sí mismo, puede hacer cualquier limpieza que necesite después del control.

Una forma de implementar la última opción es utilizar un mutex como bandera, y lo prueba con pthread_mutex_trylock() envuelto en una función para utilizar en las pruebas de bucle:

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

/* Returns 1 (true) if the mutex is unlocked, which is the 
* thread's signal to terminate. 
*/ 
int needQuit(pthread_mutex_t *mtx) 
{ 
    switch(pthread_mutex_trylock(mtx)) { 
    case 0: /* if we got the lock, unlock and return 1 (true) */ 
     pthread_mutex_unlock(mtx); 
     return 1; 
    case EBUSY: /* return 0 (false) if the mutex was locked */ 
     return 0; 
    } 
    return 1; 
} 

/* Thread function, containing a loop that's infinite except that it checks for 
* termination with needQuit() 
*/ 
void *thread_do(void *arg) 
{ 
    pthread_mutex_t *mx = arg; 
    while(!needQuit(mx)) {} 
    return NULL; 
} 

int main(int argc, char *argv[]) 
{ 
    pthread_t th; 
    pthread_mutex_t mxq; /* mutex used as quit flag */ 

    /* init and lock the mutex before creating the thread. As long as the 
    mutex stays locked, the thread should keep running. A pointer to the 
    mutex is passed as the argument to the thread function. */ 
    pthread_mutex_init(&mxq,NULL); 
    pthread_mutex_lock(&mxq); 
    pthread_create(&th,NULL,thread_do,&mxq); 

    sleep(2); 

    /* unlock mxq to tell the thread to terminate, then join the thread */ 
    pthread_mutex_unlock(&mxq); 
    pthread_join(th,NULL); 

    sleep(2); 
    return 0; 
} 

Si el hilo no es separado (por lo general no es por defecto), debe llamar al pthread_join() después de detener el hilo.Si el hilo está desacoplado, no necesita unirlo, pero no sabrá exactamente cuándo termina (o incluso aproximadamente, a menos que agregue otra forma de indicar su salida).

+0

para utilizar esta solución mutex para múltiples pthread Necesitaría un mutex por hilo, ¿verdad? recomendarías esta solución en este caso? –

+2

@RicardoCrudo No, sólo un mutex ... si 'needQuit()' bloquea con éxito, se abre justo después ... solamente 'main()' tiene el mutex durante un período prolongado de tiempo. Cualquier hilo que use 'needQuit()' para comprobar si sale se cerrará una vez que nada más tenga el mutex bloqueado, y solo lo bloquearán ellos mismos durante un momento (muy muy breve). Solo una llamada 'needQuit()' tendrá éxito a la vez, pero cada hilo seguirá obteniendo una llamada exitosa una tras otra. – Dmitri

5

Unos pequeños pensamientos:

  1. Usted está tratando de cancelar su hilo, pero si las condiciones de cancelación en su lugar es para una cancelación diferida, su thread_do() nunca será cancelado, debido a que nunca se llama a cualquier funciones que son puntos de cancelación:

    A thread's cancellation type, determined by 
    pthread_setcanceltype(3), may be either asynchronous or 
    deferred (the default for new threads). Asynchronous 
    cancelability means that the thread can be canceled at any 
    time (usually immediately, but the system does not guarantee 
    this). Deferred cancelability means that cancellation will 
    be delayed until the thread next calls a function that is a 
    cancellation point. A list of functions that are or may be 
    cancellation points is provided in pthreads(7). 
    
  2. no está uniendo el hilo en su sencillo código de ejemplo; pthread_join(3) llamar antes del final de su programa:

    After a canceled thread has terminated, a join with that 
    thread using pthread_join(3) obtains PTHREAD_CANCELED as the 
    thread's exit status. (Joining with a thread is the only way 
    to know that cancellation has completed.) 
    
Cuestiones relacionadas