pthread_kill() 与 pthread_cancel() 终止因 I/O 而阻塞的线程
pthread_kill() vs pthread_cancel() to terminate a thread blocked for I/O
在我们的服务器代码中,我们使用 poll(( 系统调用来监视客户端套接字。调用 poll(( 的超时值较大。因此,调用 poll(( 的线程被阻止用于 I/O。
根据流程,我们有一个场景,我们需要终止来自不同线程的 poll(( 中阻塞的线程。我遇到了 pthread_kill(( 和 pthread_cancel(( 函数,它们可以终止因 I/O 而阻塞的目标线程。
通过阅读手册页,这两个函数似乎都可以正常工作。互联网上很少有链接表明这两个功能使用起来都很危险。
有没有其他方法可以终止因 I/O 而阻塞的线程? 如果没有,建议使用其中哪个函数。
一个简单明了的选择是创建一个"信号"管道。也就是说,调用pipe
,获取"读取"端的文件描述符并将其添加到poll
文件描述符列表中(带POLLIN
(。然后,每当你想取消阻止正在等待poll
的线程时,只需在管道的写入端写入一个字节即可。管道收到数据后,将在被阻止的线程中返回为可读。您甚至可以通过改变写入字节的值来指定不同的"命令"。
(当然,您需要从管道中读取字节,然后才能重复使用它。
根据线程库的确切实现,线程很可能在被杀死时甚至不会从poll
返回 - 因此,您甚至可能无法实现您想要的。
您需要非常小心不要创建内存泄漏,并且仍然很可能通过杀死拥有它的线程来创建文件描述符泄漏(注意,线程资源与进程相反,不会被系统"清理"(。
通常更安全的做法是使用较短的超时周期并在两者之间轮询终止标志,或使用信号中断系统调用,然后在其自身控制下终止线程,从而释放所有分配的资源。
没有杀死线程这样的事情。
命名不佳的pthread_kill
函数是名称不佳的kill
函数的线程类似物,它发送信号进行处理。这个名字在历史上kill
有意义的,因为许多信号的默认动作是终止进程。但是,终止进程的这种默认操作并不取决于信号是发送到进程还是特定线程- 无论哪种方式,进程都会终止。
pthread_kill
唯一有用的时间是当您想在另一个线程上调用信号处理程序时。除非您确定信号处理程序不会中断任何非异步信号安全的函数,否则信号处理程序仅限于调用异步信号安全的函数,因此甚至无法结束线程的生命周期(pthread_exit
不是异步信号安全的(。
如果您同意线程最终因调用而终止,pthread_cancel
结束卡在阻塞操作中的线程的正确方法。但是,为了安全地使用它,您需要大量使用pthread_cleanup_push
和pthread_cleanup_pop
.
如果您不希望线程终止,信号是您唯一的选择。您有两种选择:
-
使用不带
SA_RESTART
sigaction
安装信号处理程序(可以是无操作(,以便导致EINTR
。由于这种方法存在固有的竞争条件(如果您在输入阻塞系统调用之前发送信号,而不是一旦它被阻塞,信号将不会执行任何操作(,因此您需要重复发送信号,并具有指数退避,以免耗尽目标的执行时间,直到目标通过其他同步机制(POSIX 信号量运行良好(确认它收到了消息。 -
安装将
longjmp
的信号处理程序。为了安全地执行此操作,您需要控制可能发生的背景;最简单的方法是在信号掩码中正常阻止它,仅在jmp_buf
在阻止呼叫周围有效时才取消屏蔽它。您调用的阻塞函数必须是异步信号安全的,并且它不需要是分配或释放资源(如open
或close
(的函数,因为当您处理信号时,您将失去它是否完成的知识。当然,jmp_buf
或指向它的指针需要是一个线程本地对象(_Thread_local
/__thread
(,才能使其正常工作。
- 如果不包含 pthread,为什么 GCC 的线程标准库实现会抛出异常?
- 使用 pthread 的多线程
- Posix 线程类和启动例程 (pthread)
- 如何修复下一个线程以使其更正确?使用 Pthread
- 如何从父线程中提取 pthread 的任务 id(tid)
- 当其中一个线程在 C++ 中使用 pthread 被杀死时,我如何保持进程的存活
- 读取另一个线程中并发运行的 pthread 的本地数据
- pthread取消成功,但在线程的100个后无法创建线程
- Pthread,杀死JNI创建的线程
- 成员变量的更新值不会在 PTHREAD 中的线程路由函数中重新排列
- 为什么使用 pthread 的 Ubuntu 中的单线程比多线程快
- 当 pthread 启动时,它是否需要互斥锁来访问之前在生成它的线程中写入的全局数据
- C++ pthread,两个线程读取一个全局变量
- pthread 在分离的线程上创建错误 11
- 是否有任何 pthread 函数可以在最后一个线程终止时调用某些内容
- pthread - 使用一个线程访问多个对象
- 停止服务器>如何验证线程是否已停止 ->pthread
- 在静态初始化期间,pthread线程变量何时开始存在
- 线程调度程序模拟:唤醒和睡眠Pthread的正确方法
- 如何在Linux上监视多线程(pthread)C++程序的每个线程行为