在Linux中,我如何找到我的进程已打开的文件句柄?

13

当我们在Unix中执行fork时,打开的文件句柄会被继承,如果我们不需要使用它们,我们应该将它们关闭。但是,当我们使用库时,可能会打开我们无法访问句柄的文件句柄。我们如何检查这些打开的文件句柄?

9个回答

18
在Linux中,您可以检查/ proc / <pid> / fd目录 - 每个打开的fd都会有一个名为句柄的文件。我几乎可以确定这种方法是不可移植的。
或者您可以使用lsof - 根据man lsof,它适用于Linux、AIX、FreeBSD和NetBSD。

18

您可以在 shell 中执行以下命令:

lsof -P -n -p _PID_

其中 PID 是您的进程 ID。


1
在 shell 上这样做的意义是什么?我该如何进入我的分叉子进程并关闭它? - sep
1
@sep: 当考虑到您的问题描述时,这个答案可能不是最好的选择,但它确实准确回答了实际问题。所以,感谢Felipe帮助我找到了我的进程句柄 :) - Superole

13

如果库正在打开你不知道的文件,那么在fork之后你如何知道它们是否需要?未导出的句柄是库的内部细节,如果库想要关闭它们,它将注册一个atfork()处理程序来关闭它们。在某些代码背后走来走去关闭它的文件句柄会导致微妙且难以调试的问题,因为当库尝试使用它正确打开但没有关闭的句柄时,它将意外报错。


4

正如 @Louis Gerbarg 的回答所提到的,这些库可能希望文件句柄在 fork() 时保持打开状态(毕竟它是父进程的几乎相同副本)。

大多数人遇到的问题出现在随后的 exec() 上。在这里,正确的解决方案是由创建句柄的库将其标记为 close-on-exec (FD_CLOEXEC)。

在被多线程程序使用的库中,存在一个竞态条件,即库创建文件句柄并在其上设置 FD_CLOEXEC(另一个线程可以在两个操作之间进行 fork())。为了解决这个问题,Linux 内核引入了 O_CLOEXEC


2
首先,你不需要太过关注你不知道的打开文件描述符。如果你知道你不会再次写入它们,关闭它们是个好主意,也不会有什么坏处 - 毕竟,你刚刚进行了fork(),这些文件描述符已经被打开两次了。但同样地,如果你让它们保持打开状态,它们也不会影响你 - 毕竟,你不知道它们的存在,也不会随意写入它们。
至于第三方库的操作,情况各异。一些库可能没有考虑到fork()的情况,可能会导致两个进程无需同步就向同一fd写入数据。另一些库可能不希望你关闭它们的fd。你需要检查一下。这就是为什么在库中随意打开文件描述符而不将其交给调用者管理是一个坏主意。
话虽如此,在回答原始问题的精神上,没有特别好的方法。你可以在文件描述符上调用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,尽管在这一点上,您大多数情况下必须回退到硬编码值(除非您正在执行极端奇怪的操作)。或者,如果您只使用Linux,可以在/ proc中搜索。

不要忘记不要关闭fds 0、1和2 - 那真的会使事情混乱。


一般来说,你不用太关心,直到达到极限并开始收到太多打开文件的错误。 - philant

1

我同意其他人关于关闭随机文件可能很危险的说法。你可能会为所有第三方工具提交一些非常有趣的错误报告。

话虽如此,如果你知道你不需要这些文件处于打开状态,你可以遍历所有有效的文件描述符(1到65535,如果我没记错的话),并关闭所有你不认识的东西。


你可以使用 getdtablesize(2) 调用来获取进程文件描述符表中的条目数量。 - Jason Coco

0

合理的库总是会有函数来释放它们分配的任何资源(例如文件句柄)。


0
只是一个链接,但看起来很有帮助:有多少个打开的文件? 在netadmintools.com上。它似乎使用/proc调查来了解进程的打开文件,不确定是否是唯一的方式还是是否有API可用。解析此类信息的文件可能会有点混乱。另外,/proc也可能被弃用了,需要进行检查。

0

这不是一个设计问题吗?在初始化打开这些文件的库之前,您的进程是否可以分叉?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接