如何终止一个正在运行的线程?

4

可能重复:
如何在pthread中终止线程

这里有一个包含启动线程的源代码,过一段时间后我想杀死它。 如何做到?且不修改线程功能

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

pthread_t test_thread;

void *thread_test_run (void *v) // I must not modify this function
{
    int i=1;
    while(1)
    {
       printf("into thread %d\r\n",i);
       i++; 
       sleep(1);
    }
    return NULL
}

int main()
{
    pthread_create(&test_thread, NULL, &thread_test_run, NULL);

    sleep (20);
    // Kill the thread here. How to do it?

   // other function are called here...

    return 0;
}

3
https://dev59.com/kHI95IYBdhLWcg3w8iv1 - David Ranieri
3
注意,直接“杀死”线程是不好的做法。每个线程都应该被适当地设计,有一种方法可以从主程序中停止它。仅仅因为存在杀死线程的功能,不意味着你应该开始以低质量的方式设计线程函数。 - Lundin
1
我建议看一下pthread_joinpthread_attr_setdetachstate... 创建一些机制来告诉线程现在需要退出,并调用pthread_join来清理使用的资源。 - user1551592
我正在使用一个外部库中的函数,这个函数包含无限循环。这个函数会在随机时间更改全局变量1次。因此,我想在全局变量被更改后终止线程。我不再需要该线程运行。 - MOHAMED
pthread_cancel(pthread_t thread); 是否可能会导致阻塞,如果线程函数正在执行系统调用? - MOHAMED
2个回答

15
你可以使用 pthread_cancel() 来终止一个线程:
int pthread_cancel(pthread_t thread);
请注意,线程可能没有机会进行必要的清理工作,例如释放锁、释放内存等。因此,您应该先使用 pthread_cleanup_push() 添加清理函数,当线程被取消时将调用这些函数。来自 man pthread_cleanup_push(3)
这些函数操作调用线程的线程取消清理处理器栈。清理处理器是在线程被取消(或其他情况下)自动执行的函数;例如,它可能会解锁互斥锁,以便其他进程中的线程可以使用它。
关于阻塞线程是否会被取消的问题,并不保证。请注意手册也提到了这一点:
线程的取消类型由 pthread_setcanceltype(3) 确定,可能是异步的或延迟的(新线程的默认值)。异步可取消性意味着线程可以随时被取消(通常立即,但系统不能保证这一点)。延迟取消意味着取消将被延迟,直到线程下一次调用是取消点的函数为止。
因此,这意味着唯一有保证的行为是在调用 pthread_cancel() 后的某个时间点取消线程。
注意:如果无法更改线程代码以添加清理处理程序,则您的另一选择是使用 pthread_kill() 杀死线程,但出于上述原因,这是一种非常糟糕的方法。

2
+1 是因为提到了 pthread_cleanup_push()。 - CCoder
pthread_cancel(pthread_t thread);会导致阻塞吗?如果线程函数正在执行系统调用,这种情况是否可能发生? - MOHAMED
@MohamedKALLEL 不,调用 pthread_cancel() 永远不会是一个阻塞调用。 - alk
@MohamedKALLEL,我误解了你的问题,pthread_cancel不会阻塞,但如果线程在另一个调用上阻塞,例如读取,那么不能保证它会立即被取消。 - iabdalkader
@iabdalkader,您的文本是否意味着一个被pthread_cancel的线程只有在到达取消点时才会被取消,而不是在执行阻塞函数(和取消点)时?这似乎不是真的,因为执行sleepselect的线程将立即被取消,它不必到达下一个取消点/函数调用。 - user1502776

4
简而言之,如果线程正在运行的代码与您合作,您可以使用任何支持的方法终止它。如果线程正在运行的代码没有与您合作,那么您甚至不应该尝试终止它。假设线程在您杀死它时持有关键锁呢?如果线程已经分配了内存并且没有其他代码可以释放该内存呢?

你的答案只有在线程运行的代码支持它的情况下才有效。否则,它可能会在保持关键锁定或分配内存后破坏线程。正如我所说,如果代码支持它,您可以使用任何它支持的方法。但是,如果您不确定代码是否支持此功能,甚至不应尝试它。 - David Schwartz
是的,pthread_cleanup_push 的目的就是添加支持取消线程的代码。 - iabdalkader
没错,但他的问题陈述了他无法更改他试图终止的代码。因此,只有在他试图终止的代码支持它时,他才能使用这种方法。但是,他可以使用他试图终止的代码支持的任何方法。如果它不支持任何方法,那么他就不能使用任何方法。 - David Schwartz
是的,非常好的观点。如果他无法更改函数的代码,即使只是添加一个对 pthread_cleanup_push 的调用,我也看不出有什么办法可以做到。 - iabdalkader
我在我的答案上放了一个注释,希望这样更清楚。 - iabdalkader

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接