如何停止在共享库中实现的阻塞 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()的主要内容,如果未能解决你的问题,请参考以下文章