当我们在Unix中执行fork时,打开的文件句柄会被继承,如果我们不需要使用它们,我们应该将它们关闭。但是,当我们使用库时,可能会打开我们无法访问句柄的文件句柄。我们如何检查这些打开的文件句柄?
/ proc / <pid> / fd
目录 - 每个打开的fd都会有一个名为句柄的文件。我几乎可以确定这种方法是不可移植的。lsof
- 根据man lsof
,它适用于Linux、AIX、FreeBSD和NetBSD。您可以在 shell 中执行以下命令:
lsof -P -n -p _PID_
其中 PID 是您的进程 ID。
如果库正在打开你不知道的文件,那么在fork之后你如何知道它们是否需要?未导出的句柄是库的内部细节,如果库想要关闭它们,它将注册一个atfork()处理程序来关闭它们。在某些代码背后走来走去关闭它的文件句柄会导致微妙且难以调试的问题,因为当库尝试使用它正确打开但没有关闭的句柄时,它将意外报错。
正如 @Louis Gerbarg 的回答所提到的,这些库可能希望文件句柄在 fork()
时保持打开状态(毕竟它是父进程的几乎相同副本)。
大多数人遇到的问题出现在随后的 exec()
上。在这里,正确的解决方案是由创建句柄的库将其标记为 close-on-exec (FD_CLOEXEC
)。
在被多线程程序使用的库中,存在一个竞态条件,即库创建文件句柄并在其上设置 FD_CLOEXEC
(另一个线程可以在两个操作之间进行 fork()
)。为了解决这个问题,Linux 内核引入了 O_CLOEXEC
。
int newfd = dup(oldfd);
if (newfd > 0)
{
close(newfd);
close(oldfd);
}
但那时你最好一开始就说close(oldfd)
,忽略任何EBADF错误。
假设您仍然想采取关闭所有内容的核选项,则需要找到可能的最大打开文件描述符数。假设从1到65,535不是一个好主意。首先,fds从0开始,当然,也没有特定的上限定义。为了可移植性,POSIX的sysconf(_SC_OPEN_MAX)
应该告诉您,在任何合理的POSIX系统上,尽管严格来说它是可选的。如果您感到有些神经质,请检查返回值是否为-1,尽管在这一点上,您大多数情况下必须回退到硬编码值(除非您正在执行极端奇怪的操作)。或者,如果您只使用Linux,可以在/ proc中搜索。
不要忘记不要关闭fds 0、1和2 - 那真的会使事情混乱。
我同意其他人关于关闭随机文件可能很危险的说法。你可能会为所有第三方工具提交一些非常有趣的错误报告。
话虽如此,如果你知道你不需要这些文件处于打开状态,你可以遍历所有有效的文件描述符(1到65535,如果我没记错的话),并关闭所有你不认识的东西。
合理的库总是会有函数来释放它们分配的任何资源(例如文件句柄)。
这不是一个设计问题吗?在初始化打开这些文件的库之前,您的进程是否可以分叉?