如何从循环外部杀死无限循环中的pthread?

时间:2011-10-31 23:41:36

标签: c memory-leaks pthreads threadpool

我创建了一个线程,并将其置于无限循环中。使用 valgrind 检查代码时出现内存泄漏。这是我的代码:

#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;
}

所以在main中创建一个线程,并且一直运行thread_do()。有没有办法在2秒后从 main 内部杀死它?我已经尝试了pthread_detach(th)pthread_cancel(th),但我仍然会泄漏。

2 个答案:

答案 0 :(得分:35)

正如@sarnold指出的那样,默认情况下,如果没有调用任何取消点的函数,就无法使用pthread_cancel()取消您的线程......但是可以通过使用pthread_setcanceltype()来设置线程的取消类型为异步而不是延迟。为此,在开始循环之前,在线程函数的开头附近添加pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);之类的内容。然后,您可以通过pthread_cancel(th)调用main()来终止该主题。

但请注意,以这种方式取消线程(无论是否异步)都不会清除线程函数中分配的任何资源(如Kevin在评论中所述)。为了做到这一点,你可以:

  • 确保线程在退出之前不执行任何需要清理的操作(例如,使用malloc()分配缓冲区)
  • 确保在线程退出
  • 后,在其他位置的线程之后有一些清理方法
  • 使用pthread_cleanup_push()pthread_cleanup_pop()添加清理处理程序,以便在取消线程时清理资源。请注意,如果取消类型是异步的,这仍然存在风险,因为在分配资源和添加清理处理程序之间可以取消线程。
  • 避免使用pthread_cancel()并让线程检查一些条件以确定何时终止(将在长时间运行的循环中检查)。由于您的线程会自行检查终止,因此它可以在检查后执行所需的任何清理。

实现最后一个选项的一种方法是使用互斥锁作为标志,并使用包含在函数中的pthread_mutex_trylock()对其进行测试,以便在循环测试中使用:

#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;
}

如果线程未分离(通常不是默认情况下),则应在停止线程后调用pthread_join()。如果线程已分离,则您不需要加入它,但您不会确切地知道它何时终止(或者甚至大致,除非您添加另一种方式来指示其退出)。

答案 1 :(得分:5)

一些小小的想法:

  1. 您正在尝试取消您的主题,但如果适用的取消政策是延期取消,则thread_do()永远不会被取消,因为它永远不会调用任何取消点的功能:
  2.     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. 您没有加入简单示例代码中的主题;在程序结束前致电pthread_join(3)
    2.     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.)