2011-10-31 89 views
20

我创建了一个线程,并将其放入无限循环。当我使用valgrind检查代码时,我得到内存泄漏。这里是我的代码:如何从该循环外部杀死处于无限循环中的pthread?

#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秒后从内部杀死它?我试过pthread_detach(th)pthread_cancel(th),但我仍然有泄漏。

+3

取消pthreads意味着线程没有机会清理它分配的任何内存。 –

+2

好吧,我只通过一个全局'keepalive = 1'来解决这个问题。然后我把while(1)'改为'while(keepalive)'。为了杀死线程,我只需要将变量keepalive的值更改为0即可! – Pithikos

回答

32

由于@sarnold指出,在默认情况下你的线程不能与pthread_cancel()无需调用是取消点的任何功能,取消了......但是,这可以通过使用pthread_setcanceltype()来将线程的取消类型设置为异步而不是延迟。要做到这一点,在开始循环之前,你需要在线程函数启动附近添加类似pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);的东西。您可以通过从main()调用pthread_cancel(th)来终止该线程。

请注意,这样取消线程(无论是否异步)并不会清除线程函数中分配的任何资源(如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()。如果线程已分离,则不需要加入它,但不知道它何时终止(甚至大约,除非添加另一种方式来指示它退出)。

+0

使用这个互斥体解决方案为多个pthread我需要一个互斥体每个线程,对不对?你会在这种情况下推荐这个解决方案吗? –

+2

@RicardoCrudo不,只有一个互斥体...如果'needQuit()'成功锁定它,它会在......之后解锁它,只有'main()'持续一段时间的互斥锁。任何使用'needQuit()'检查是否退出的线程都会退出,一旦锁定了互斥锁,它们将只锁定它自己一段时间(非常非常短暂)。一次只能有一个'needQuit()'调用成功,但每个线程仍会一个接一个地成功调用。 – Dmitri

5

一些小的想法:

  1. 你试图取消线程,但如果地方取消政策是延期取消,您thread_do()将永远不会被取消,因为它从来没有任何要求功能是取消点:

    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. 您未加入您的简单示例代码中的线程;你的程序结束之前调用pthread_join(3)

    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.)