¿Cómo puedo matar un pthread que está en un bucle infinito, desde fuera de ese bucle?


Creo un hilo y lo pongo en un bucle infinito. Tengo pérdidas de memoria al comprobar el código con valgrind. Aquí está mi código:

#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 matarlo desde adentro main después de 2 segundos? He intentado ambos pthread_detach(th) y pthread_cancel(th) pero todavía tengo fugas.

Author: Pithikos, 2011-11-01

2 answers

Como @sarnold señaló, por defecto su hilo no se puede cancelar con pthread_cancel() sin llamar a ninguna función que sea puntos de cancelación... pero esto se puede cambiar usando pthread_setcanceltype() para establecer el tipo de cancelación del hilo en asíncrono en lugar de diferido. Para hacer eso, agregarías algo como pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); cerca del inicio de tu función de subproceso, antes de iniciar el bucle. Entonces podrías terminar el hilo llamando a pthread_cancel(th) desde main().

Tenga en cuenta, sin embargo, que la cancelación hilos de esta manera (ya sea asíncrono o no) no limpia los recursos asignados en la función de hilo (como señaló Kevin en un comentario). Para hacer esto limpiamente, usted puede:

  • Asegúrese de que el subproceso no haga nada que necesite limpiar antes de salir (por ejemplo, usando malloc() para asignar un búfer)
  • Asegúrese de que tiene alguna forma de limpiar después del hilo en otro lugar, después de que el hilo salga
  • Use pthread_cleanup_push() y pthread_cleanup_pop() para agregar controladores de limpieza para limpiar recursos cuando se cancela el hilo. Tenga en cuenta que esto sigue siendo arriesgado si el tipo de cancelación es asíncrono, porque el subproceso podría cancelarse entre la asignación de un recurso y la adición del controlador de limpieza.
  • Evite usar pthread_cancel() y haga que el subproceso verifique alguna condición para determinar cuándo terminar (lo que se verificaría en bucles de larga duración). Dado que su hilo comprueba la terminación en sí, puede hacer cualquier limpieza que necesite después de la comprobación.

Uno la forma de implementar la última opción es usar un mutex como indicador, y probarlo con pthread_mutex_trylock() envuelto en una función para usar 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 subproceso no está separado (generalmente no lo está por defecto), debe llamar a pthread_join() después de detener el subproceso. Si el hilo está separado, no necesitas unirlo, pero no sabrás exactamente cuándo termina (o incluso aproximadamente, a menos que agregues otra forma de indicar su salida).

 34
Author: Dmitri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-01 06:50:35

Unos pequeños pensamientos:

  1. Usted está tratando de cancelar su hilo, pero si la política de cancelación en vigor es para una cancelación diferida, su thread_do() nunca será cancelado, porque nunca llama a ninguna función 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).
  1. No estás uniendo el hilo en tu código de ejemplo simple; llama pthread_join(3) antes del final de tu 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.)
 5
Author: sarnold,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-07 01:05:28