【发布时间】:2012-12-25 10:33:36
【问题描述】:
帮助客户解决他们遇到的问题。我更像是一个系统管理员/DBA 人,所以我正在努力帮助他们。他们说这是内核/环境中的错误,在我坚持认为它存在于他们的代码中或寻求操作系统的供应商支持之前,我试图证明或反驳这一点。
发生在 Red Hat 和 Oracle Enterprise Linux 5.7(和 5.8)上,应用程序是用 C++ 编写的
他们遇到的问题是主线程启动了一个单独的线程来执行可能长时间运行的 TCP connect() [客户端连接到服务器]。 如果“长时间运行”方面花费的时间过长,他们会取消线程并启动另一个线程。
这样做是因为我们不知道服务器程序的状态:
- 服务器程序启动并运行 --> 立即接受连接
- 服务器程序未运行,机器和网络正常 --> 连接 立即失败,错误“连接被拒绝”
- 机器或网络崩溃或关闭 --> 连接需要很长时间 失败并出现错误“没有到主机的路由”
问题是取消已锁定互斥锁的线程 (设置清除处理程序以解锁互斥锁)有时不会解锁互斥锁。
这使得主线程在试图锁定互斥锁时挂起。
详细环境信息:
- glibc-2.5-65
- glibc-2.5-65
- libcap-1.10-26
- kernel-debug-2.6.18-274.el5
- glibc-headers-2.5-65
- glibc-common-2.5-65
- libcap-1.10-26
- kernel-doc-2.6.18-274.el5
- kernel-2.6.18-274.el5
- kernel-headers-2.6.18-274.el5
- glibc-devel-2.5-65
代码是用以下方式构建的: c++ -g3 tst2.C -lpthread -o tst2
非常感谢任何建议和指导
【问题讨论】:
-
你如何用互斥锁取消线程?如果你只是简单地杀死线程,那么析构函数(我假设互斥锁被解锁)很有可能永远不会运行。
-
大多数时候有人说操作系统有错误,但他们的应用程序没有,他们的应用程序有。这是一种由这种想法带来的自我实现的预言:糟糕的想法,糟糕的代码。如果他们真的只是在冷死地杀死线程,那么当然不会释放互斥锁,也不会运行任何代码来这样做。这是他们自己的设计问题。
-
IIRC,对于 pthreads,无论如何,取消线程本身永远不会释放该线程持有的锁或其他资源 - 必须编写线程以处理特定点的取消并在之前处理必要的清理它消失了......
-
一种可能是让主线程关闭套接字,而不是取消线程。这将导致另一个线程中的
connect(...)以EBADF失败,这可以被适当地检测和处理。 -
“如果一名机械师在维修飞机的过程中死亡,我们如何才能自动让这架飞机重新投入使用?”您只是不要那样做,这不是很明显吗?为什么要取消线程呢?不会有什么害处吧?