题
我有一个程序:
- 有一个主线程 (1),它启动一个服务器线程 (2) 和另一个线程 (4)。
- 服务器线程 (2) 执行accept(),然后创建一个新线程 (3) 来处理连接。
在某个时刻,线程 (4) 执行 fork/exec 来运行另一个程序,该程序应连接到线程 (2) 正在侦听的套接字。有时会失败或花费不合理的长时间,并且诊断起来非常困难。如果我跟踪系统,看起来 fork/exec 已经工作,接受已经发生,新线程 (4) 已经创建..但该线程中没有任何反应(使用 strace -ff,相关 pid 的文件为空)。
有任何想法吗?
解决方案
我得出的结论是,可能是这样的现象:
http://kerneltrap.org/mailarchive/linux-kernel/2008/8/15/2950234/thread
因为该错误在我们的开发系统上很难触发,但通常是由在大型共享计算机上运行的用户报告的;分叉的应用程序还会启动一个 JVM,它本身会分配很多线程。该问题还与正在加载的机器和大量内存使用有关(我们有一台具有 128Gb RAM 的机器,进程大小可能为 10-100G)。
我一直在阅读 O'Reilly pthreads 书,其中解释了 pthread_atfork(),并建议使用在启动时从主进程分叉出来的“代理父”进程,子进程从中运行。它还建议使用预先创建的线程池。这两个看起来都是好主意,所以我将至少实现其中之一。
其他提示
这看起来像是一个死锁状态。寻找阻塞函数,比如accept(),问题应该就在那里。
将代码减少到仍然具有行为的最小可能大小并将其发布在此处。要么您找到答案,要么我们能够找到答案。
顺便提一句 - http://lists.samba.org/archive/linux/2002-February/002171.html 似乎 exec 的 pthread 行为没有明确定义,可能取决于您的操作系统。
fork 和 exec 之间有任何代码吗?这可能是一个问题。
使用多线程和分叉时要非常小心。大多数 glibc/libstdc++ 是线程安全的。如果分叉线程以外的线程在分叉执行时持有锁,则分叉进程将继承处于当前锁定状态的互斥体。新进程永远不会看到这些互斥锁被解锁。欲了解更多信息,请参阅 man pthread_atfork
.
我刚刚遇到了同样的问题,最后发现 fork() 复制所有线程. 。现在想象一下,在所有运行双实例的线程的 fork() 之后,你的程序会做什么......
以下规则来自 “关于 fork() 和 Pthreads 的迷你指南”:
1-你不想那样做。
2-如果您需要 fork() 那么:只要可能,请在启动任何线程之前叉()所有孩子。
编辑:尝试过,fork() 不会复制线程。