当我们在Unix中执行fork时,会继承打开的文件句柄,如果我们不需要使用它们,我们应该关闭它们。但是,当我们使用库时,可能会打开文件句柄,我们无法访问该句柄。我们如何检查这些打开的文件句柄?
答案 0 :(得分:16)
在Linux中,您可以检查/proc/<pid>/fd
目录 - 对于每个打开的fd,都会有一个名为handle的文件。我几乎可以肯定这种方式是不便携的。
另外,根据lsof
,您可以使用man lsof
- 适用于Linux,AIX,FreeBSD和NetBSD。
答案 1 :(得分:14)
如果库是打开你不知道的文件,你怎么知道他们在fork之后不需要它们?未导出的句柄是内部库详细信息,如果库希望它们关闭,它将注册一个atfork()处理程序来关闭它们。在一些代码后面走动,关闭其背后的文件句柄将导致难以调试的问题,因为当它试图使用它知道正确打开但未关闭的句柄时,库会意外地出错。
答案 2 :(得分:14)
你可以从shell做到:
lsof -P -n -p _PID_
PID 是您的流程pid。
答案 3 :(得分:5)
正如在@Louis Gerbarg的回答中所提到的,库可能期望文件句柄在fork()
上保持打开(毕竟这应该是父进程的几乎相同的副本)。 / p>
大多数人遇到的问题是exec()
常常跟随fork()
。在这里,正确的解决方案是创建句柄的库,将它们标记为close-on-exec(FD_CLOEXEC
)。
在多线程程序使用的库上,创建文件句柄的库和在其上设置FD_CLOEXEC
之间存在竞争条件(两个操作之间的另一个线程可以fork()
)。为了解决这个问题,在Linux内核中引入了O_CLOEXEC
。
答案 4 :(得分:2)
首先,您并不需要关心您不了解的打开文件描述符。如果你知道你不会再给他们写信,那么关闭他们是一个好主意而且不会受到伤害 - 毕竟你只是做了一个fork(),fds打开了两次。但同样地,如果你把它们打开,它们也不会打扰你 - 毕竟,你不了解它们,你可能不会随意写信给它们。
至于你的第三方图书馆会做什么,无论哪种方式,这都是一个小问题。有些人可能不希望遇到fork()的情况,并且可能最终意外地从两个进程写入相同的fd而没有任何同步。其他人可能不希望你关闭他们的fds。你必须检查。这就是为什么在库中随机打开文件描述符而不是让它给调用者进行管理是个坏主意。
所有这一切,本着回答原始问题的精神,没有一个特别好的方法。您可以在文件描述符上调用dup()
或dup2()
;如果它已关闭,则呼叫将以EBADF
失败。所以你可以说:
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的返回值,不过在这一点上你大部分都必须依靠硬编码值(1024应该没问题,除非你做的事非常奇怪)。或者,如果您特定于Linux,那么您可以在/ proc中进行挖掘。
不要忘记不关闭fds 0,1和2 - 这可能会让事情变得混乱。
答案 5 :(得分:1)
我同意其他人关于关闭随机文件危险的说法。您最终可能会为所有第三方工具提交一些非常有趣的错误报告。
也就是说,如果您知道,您将无需打开这些文件,您可以随时浏览所有有效的文件描述符(1到65535,IIRC)并关闭所有内容不承认。
答案 6 :(得分:0)
合理的库将始终具有释放已分配的任何资源(例如文件句柄)的函数。
答案 7 :(得分:0)
只是一个链接,但它似乎很有帮助:How many open files?在netadmintools.com。它似乎使用/ proc调查来了解进程的打开文件,不确定这是否是唯一的方法或是否有API。解析此类信息的文件可能有点......凌乱。此外,/ proc也可能已被弃用,需要检查。
答案 8 :(得分:0)
这不是设计问题吗?在初始化打开这些文件的库之前,您的进程是否可以进行分叉?