如何停止在共享库中实现的阻塞 pthread_join()

Posted

技术标签:

【中文标题】如何停止在共享库中实现的阻塞 pthread_join()【英文标题】:How to stop a blocking pthread_join() implemented in a shared library 【发布时间】:2019-01-14 03:26:22 【问题描述】:

我的代码在程序退出之前从第三方库调用了一个函数。不幸的是,被调用的函数阻塞了主线程,这是由.so 库中的pthread_join() 引起的。

由于它在库中,这是我无法控制的,我正在徘徊如何打破它,以便主线程可以继续

附加使用gdb的信息:

0x00007ffff63cd06d in pthread_join (threadid=140737189869312, thread_return=0x0)
    at pthread_join.c:89
89          lll_wait_tid (pd->tid);
Missing separate debuginfos, use: debuginfo-install keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64 libcom_err-1.41.12-23.el6.x86_64 libselinux-2.0.94-7.el6.x86_64 openssl-1.0.1e-57.el6.x86_64

提前致谢。

【问题讨论】:

大概它调用pthread_join() 是有充分理由的。即使您以某种方式成功击败了该调用,结果也可能是崩溃或其他不当行为,因为它正在等待的线程可能仍然处于活动状态并尝试使用数据结构,而它们在进程退出期间被拆除。更好的方法可能是调查为什么 pthread_join() 调用正在等待的线程没有退出 - 如果你能解决这个问题,那么 pthread_join() 调用将很快返回,问题将得到妥善解决。跨度> 虽然我同意上述评论,但您可以使用覆盖 pthread_join 方法的 LD_PRELOAD 预加载共享库。 那几乎肯定是灾难性的。 @JeremyFriesner 谢谢,杰里米。我完全理解你的建议,显然这也是我一直在努力的目标。实际上这个问题源于我从 GLIBC 2.12 到 GLIBC 2.14 的更改。库中的函数运行良好,在 GLIBC 2.12 中不会调用 pthread_join。在我迁移到 GLIBC 2.14(对于其他一些库)之后,就产生了这个问题。您对可能的原因有任何线索吗? 库如何知道哪个线程是主线程?它不是阻塞了一些之前碰巧调用库函数的特定线程吗? 【参考方案1】:

该库旨在让调用线程等待某事完成。由于您无法更改库的设计,因此只需从无事可做的线程中调用该库即可。

通过您设计交互的方式,您可以获得所需的任何语义。如果您希望调用线程稍后在方便时获得结果,您可以使用 promise/future。您可以将调用线程设计为等待一定时间然后超时。在超时的情况下,如果你不需要结果,你可以忽略它,或者你可以设计一些方法来检查并在以后得到结果。您还可以让调用库的线程对结果执行任何需要执行的操作,这样调用线程就不必担心了。

只需隔离您无法控制的代码,并围绕它编写任何您需要的代码,以获得您的代码所需的行为。库需要调用它的线程等到它完成,所以隔离调用它的线程并让库拥有它想要的东西。

【讨论】:

谢谢,大卫。实际上在我的主线程中,我确实分离了一个调用库的线程。我发现,当分离的线程被销毁时,库中的阻塞线程仍然存在,从而阻塞了主线程。我很好奇为什么会这样。 我不明白你所说的“阻塞主线程”到底是什么意思。 很抱歉让您感到困惑。 “阻塞主线程”是指程序下一个退出,即使它到达main() 的最后一行。 @lichgo 可能是因为图书馆仍在做它认为重要的事情。它是否提供某种关机功能? 嗨,大卫。实际上我调用的函数正是它的关闭函数。它在 GLIBC 2.12 中运行良好。在我迁移到 GLIBC 2.14 之后,就产生了这个问题。【参考方案2】:

如果你调用exit,进程会终止而不关闭其他线程。

如果您有一个正在等待的线程的pthread_t 句柄,您也许可以在其上调用pthread_cancel,但如果应用程序和库不准备处理线程取消,则会导致其他问题。 (取消线程确实pthread_join 将无济于事,因为关机将阻塞pthread_join 等待的同一线程。)

一般来说,找出为什么pthread_join 调用在您的环境中无限期等待(也就是说,为什么另一个线程没有终止)并修复它可能是一个更好的主意.

【讨论】:

以上是关于如何停止在共享库中实现的阻塞 pthread_join()的主要内容,如果未能解决你的问题,请参考以下文章

这是如何在 swift 4 中实现的?

命令建议是如何在 bash shell 中实现的?

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

有限自动机是如何在代码中实现的?

Java varargs 是如何在内存中实现的

fseek() 是如何在文件系统中实现的?