文件描述符如何在以后被回收和重用?

lor*_*ire 5 linux system-calls file-descriptors

在 C 和 C++ 的上下文中,close()系统调用是内核回收 fd 并稍后open()在同一进程生命周期中调用时重用它的唯一方法吗?多线程程序呢?

Bas*_*tch 4

仔细阅读close(2)高级 Linux 编程

您的表述是错误的: close 是一个系统调用(在Linux 的syscalls(2)中列出),应用程序通过它告诉内核释放资源(而不是相反)。您可以使用strace(1)来了解某些命令或进程执行的系统调用。另请参见pthreads(7)credentials(7)fork(2)execve(2)clone(2)

是的,文件描述符(以及虚拟内存中的地址空间,请参阅mmap(2) )对于给定进程的所有线程都是通用的。但是,您可能(很少)直接使用低级clone(2)系统调用创建“线程”(实际上仅由pthreads等线程库的实现者使用),并且在不太可能的情况下,您不使用不同 的东西。但直接打电话却是一门黑魔法。CLONE_FILESclone

对于 pid 1234 的给定进程,在 Linux 上,您可以通过查询文件描述符集(在proc(5)中)/proc/1234/fd/ 和内存映射/proc/1234/maps(等等...中有许多有用的文件和链接/proc/1234)。从进程内部,您可以使用/proc/self/fd/- 例如作为opendir(3)的参数

当然,文件描述符更多的是POSIX或 Linux 的东西,而不是标准的C99C++11的东西。例如,fileno(3) & open是在 POSIX 中定义的,而不是在 C99 中定义的。

因此,如果您看到给定的数字 - 例如 49 - 被open多次返回,那是因为程序的其他部分(可能在某个库内,在另一个线程中)调用了close 49。内核永远不会“神奇地”关闭文件描述符(进程终止时除外)无需询问。您可以使用调试器stracegdb 在调试器上设置断点(可能是条件断点)close

  • @lordofire:如果您尝试调试程序以找出文件描述符(例如49)在哪里关闭(即您有源代码,并且可以编辑它并重新编译),您可能需要查看[fstat(2)](http://man7.org/linux/man-pages/man2/fstat.2.html) 系统调用。如果文件描述符 49 打开,则“fstat(49, buf)”返回 0(并填充“buf”),如果关闭,则返回 -1。因此,如果您怀疑函数 foo() 调用了 close(49),那么您应该在调用 foo() 之前和之后调用 fstat(49, buf)。 (3认同)