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

Posted

技术标签:

【中文标题】如何从循环外部杀死处于无限循环中的 pthread?【英文标题】:How can I kill a pthread that is in an infinite loop, from outside that loop? 【发布时间】:2011-12-19 03:34:16 【问题描述】:

我创建了一个线程并将其放入无限循环中。使用 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) 我都试过了,但还是有泄漏。

【问题讨论】:

取消pthreads意味着线程没有机会清理它分配的任何内存。 好的,我通过一个全局的keepalive=1 解决了这个问题。然后我将while(1) 更改为while(keepalive)。现在要终止线程,我只需将变量 keepalive 的值更改为 0,瞧! 【参考方案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).
    您没有加入简单示例代码中的线程;在程序结束前致电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.)

【讨论】:

【参考方案2】:

正如@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()。如果线程是分离的,你不需要加入它,但你不会确切知道它何时终止(或者甚至大约,除非你添加另一种方式来指示它的退出)。

【讨论】:

要将此互斥锁解决方案用于多个 pthread,我需要每个线程一个互斥锁,对吗?在这种情况下你会推荐这个解决方案吗? @RicardoCrudo 不,只有一个互斥锁...如果needQuit() 成功锁定它,它会在...之后立即解锁它...只有main() 长时间持有互斥锁。任何使用needQuit() 来检查是否退出的线程都会在没有其他任何东西锁定互斥锁后退出,并且它们只会在(非常非常短暂的)片刻内自行锁定它。一次只能成功调用一次needQuit(),但每个线程还是会一个接一个地调用成功。 是在 threadFunc 中的 pthread_cond_wait(&amp;c, &amp;mtx); 中等待时异步取消应该起作用,我试过但没有成功

以上是关于如何从循环外部杀死处于无限循环中的 pthread?的主要内容,如果未能解决你的问题,请参考以下文章

lldb - 如何杀死卡在无限循环中的命令

Python:如何杀死无限循环?

Apache Spark:从IDE远程运行作业时的无限循环

C++:Linux上的pthread状态监控

从睡眠中唤醒主线程

如何打破 C 中的无限 for(;;) 循环?