取消locking互斥锁的线程不会解锁互斥锁

帮助客户解决他们遇到的问题。 我更像是一个系统pipe理员/数据库pipe理员,所以我正在努力帮助他们。 他们说这是内核/环境中的一个错误,我试图在我坚持认为它在代码中或者寻求供应商支持操作系统之前certificate或者反驳。

在Red Hat和Oracle Enterprise Linux 5.7(和5.8)上运行,应用程序是用C ++编写的

他们遇到的问题是主线程启动一个单独的线程来执行潜在的长时间运行的TCP连接()[client to server]。 如果“长时间运行”方面花费太长时间,则取消该线程并启动另一个线程。

这是因为我们不知道服务器程序的状态:

  • 服务器程序启动并运行 – >连接立即被接受
  • 服务器程序未运行,机器和networking正常 – >连接立即失败,错误“连接被拒绝”
  • 机器或networking崩溃或closures – >连接需要很长时间才会失败,错误“无路由到主机”

问题是取消locking互斥锁的线程(清理处理程序设置为解锁互斥锁)有时不会解锁互斥锁。

这使主线程挂起来试图locking互斥锁。

详细的环境信息:

  • 的glibc-2.5-65
  • 的glibc-2.5-65
  • 的libcap-1.10-26
  • 内核debugging2.6.18-274.el5
  • glibc的报头-2.5-65
  • 的glibc-共2.5-65
  • 的libcap-1.10-26
  • 内核DOC-2.6.18-274.el5
  • 内核2.6.18-274.el5
  • 内核头文件,2.6.18-274.el5
  • 的glibc-devel的-2.5-65

代码是用c ++ -g3 tst2.C -lpthread -o tst2构build的

任何意见和指导,不胜感激

Solutions Collecting From Web of "取消locking互斥锁的线程不会解锁互斥锁"

被取消的线程无法解锁它们所持有的互斥锁是正确的,您需要安排这些手动发生,这可能会非常棘手,因为您需要非常小心地在每个可能的取消点周围使用正确的清理处理程序。 假设你正在使用pthread_cancel取消线程并使用pthread_cancel来设置清理处理程序来解锁互斥体,那么有几种方法可以尝试,这样做可能会更简单,因此可能更加可靠。

使用RAII来解锁互斥将会更可靠。 在GNU / Linux上, pthread_cancel是通过__cxxabi::__forced_unwind类型的一个特殊的例外来__cxxabi::__forced_unwind ,所以当一个线程被取消的时候,抛出一个异常并且栈被解开。 如果一个互斥体被RAII类型锁定,那么它的析构函数将保证在堆栈被__forced_unwind异常解除时运行。 Boost Thread提供了一个包装Pthread的便携式C ++库,使用起来更容易。 它提供了RAII类型的boost::mutex和其他有用的抽象。 Boost Thread也提供了自己的“线程中断”机制,类似于Pthread的取消,但不一样,Pthread取消点(如connect )不是Boost线程中断点,这对于某些应用程序可能有帮助。 然而,在你的客户的情况下,因为取消点是打断connect呼叫,他们可能会想要坚持Pthread取消。 GNU / Linux的(非可移植的)方式实现取消作为异常,意味着它可以很好地与boost::mutex

当你用C ++编写时,真的没有理由显式地锁定和解锁互斥,恕我直言,C ++的最重要和最有用的特性是析构函数,它是自动释放资源(如互斥锁)的理想工具。

另一个选择是使用一个健壮的互斥体,它是通过在初始化互斥体之前在pthread_mutexattr_setrobust上调用pthread_mutexattr_setrobust创建的。 如果一个线程在持有可靠的互斥体的情况下死亡,内核将记录下来,以便下一个尝试锁定互斥体的线程获得特殊的错误代码EOWNERDEAD 。 如果可能,新线程可以使线程保护的数据再次保持一致,并获取互斥量的所有权。 这比使用RAII类型来锁定和解锁互斥锁要困难得多。

一个完全不同的方法是决定是否确实需要在调用connect保持互斥锁。 在缓慢的操作中持有互斥体不是一个好主意。 你不能调用connect然后如果成功锁定互斥锁,并更新共享数据受互斥量保护?

我的首选是使用Boost Thread并避免长时间持有互斥锁。

他们遇到的问题是主线程启动一个单独的线程来执行潜在的长时间运行的TCP连接()[client to server]。 如果“长时间运行”方面花费太长时间,则取消该线程并启动另一个线程。

微不足道的修复 – 不要取消线程。 它有害吗? 如有必要,进行线程检查(当connect最终完成时)是否仍然需要连接,如果没有,则关闭它,释放互斥锁并终止。 你可以用一个由互斥锁保护的布尔变量来做到这一点。

另外,线程在等待网络I / O时不应该保持互斥。 互斥量只能用于速度较快,主要受CPU限制或可能受本地磁盘限制的情况。

最后,如果你觉得你需要从外面伸手去强迫一个线程去做某件事,那就退后一步。 为该线程编写了代码。 如果你觉得需要的话,那就意味着你没有编写这个线程去做你真正想做的事情。 解决的办法是修改线程来做什么,只有你想要的。 那么你不必从外面“推”它。