信号处理程序中的 pthread_exit()

Posted

技术标签:

【中文标题】信号处理程序中的 pthread_exit()【英文标题】:pthread_exit() in signal handler 【发布时间】:2012-12-03 16:54:02 【问题描述】:

(这个问题可能与pthread_exit in signal handler causes segmentation fault 有点相关)我正在编写一个预防铅锁库,其中总是有一个检查线程在执行图形处理并检查是否存在死锁,如果是,则表示其中一个冲突线程。当该线程捕获信号时,它会释放它拥有的所有互斥体并退出。有多个资源互斥锁(显然)和一个临界区互斥锁,所有获取、释放资源锁和进行图计算的调用都必须先获取此锁。现在问题出现了。由于有 2 个竞争(不包括检查线程)线程,有时在一个线程被杀死后程序会死锁。在 gdb 中,它说死线程拥有关键区域锁但从未释放它。在信号处理程序中添加断点并单步执行后,在 pthread_exit() 之前似乎锁属于其他人(如预期的那样),但所有权在 pthread_exit() 之后神奇地转到了该线程.. 我能想到的唯一猜测是要被杀死的线程在尝试获得临界区锁时阻塞在 pthread_mutex_lock(因为它想要另一个资源互斥锁),然后信号来了,中断了 pthread_mutex_lock。既然这个调用不是信号证明的,那么奇怪的事情发生了?就像信号处理程序可能已经返回并且该线程获得锁然后退出一样? Idk.. 任何见解都值得赞赏!

【问题讨论】:

谁锁定周期性检查器以防止竞争条件?您是否以某种方式获取锁以对抗获取任何锁?计时器可以随时执行,信号处理程序可以中断任何事情,包括pthread_mutex_lock(即使它没有阻塞)。我不知道 Linux 提供了哪些具体措施来解决这个问题,但你可能会提到你做了什么。 看看下面的链接能不能帮到你:(1) ***.com/questions/13305422/… (2) ***.com/questions/13309415/… @Potatoswatter 不确定我是否完全理解您的问题,检查器仅获取 cr 锁,检查资源图中的周期,如果是,则发出信号某人死亡并返回睡眠 1 秒。这就是它所做的一切。特别是在测试用例中,我有 2 个线程和 2 个资源互斥锁,确实发生了竞争条件,但更糟糕的情况检查器会在 1 秒后发现这一点并杀死某人。这确实有效,偶尔.. 我认为我的回答已经很好地涵盖了所有内容,但是我加粗的文字对于您似乎遇到的问题特别重要:无论您做什么,都没有安全的方法来终止一个线程等待锁定互斥体。 【参考方案1】:

pthread_exit 不是异步信号安全的,因此您可以从信号处理程序调用它的唯一方法是确保信号不会中断任何非异步信号安全的函数。

作为一般原则,使用信号作为与线程通信的方法通常是一个非常糟糕的主意。您最终会混合两个本身已经足够困难的问题:线程安全(线程之间的正确同步)和单个线程内的重入。

如果您使用信号的目标只是指示线程终止,那么更好的机制可能是pthread_cancel。然而,为了安全地使用它,将被取消的线程必须在适当的点设置取消处理程序和/或在不安全时暂时禁用取消(使用pthread_setcancelstate)。另外,请注意pthread_mutex_lock 不是取消点。没有没有安全的方法来中断被阻塞等待获取互斥锁的线程,所以如果您需要这样的可中断性,您可能需要使用条件变量进行更精细的同步设置(condvar 等待是可取消的),或者你可以使用信号量而不是互斥体。

编辑:如果您确实需要一种方法来终止等待互斥锁的线程,您可以将对 pthread_mutex_lock 的调用替换为对您自己的函数的调用,该函数循环调用 pthread_mutex_timedlock 并检查每次超时时退出标志。

【讨论】:

但是信号会中断非异步信号安全功能。 @user1095108:如果您在调用这些函数时保持信号被屏蔽,则不会。但如果它们中的任何一个被阻塞,它就会破坏信号的目的 为什么?信号的目的可以是中断所述阻塞功能。以epoll_wait() 为例。 @user1095108:如果它是一个 AS-safe 功能,您正在中断,那么是的,它工作正常。问题是当它是阻塞的 AS 不安全函数时。那么你不能从处理程序中pthread_exit 你能举一些 AS-unsafe 函数的例子吗?此外,信号可能会延迟。所以AS-unsafe函数退出后会触发。

以上是关于信号处理程序中的 pthread_exit()的主要内容,如果未能解决你的问题,请参考以下文章

终止线程执行的3种方法(pthread_exit()pthread_cancel()return)

Unix高级环境编程学习小结

进程-

进程终止,环境表和环境变量操作

pthread_exit在main线程中的用处

从 C++ 中的 posix 信号处理程序获取对象属性