当我关闭文件描述符时会发生什么?


16

我正在尝试使用文件描述符获取整个图片。假设我有process1,它最初具有这些文件描述符:

 _process1_
|          |
| 0 stdin  |
| 1 stdout |
| 2 stderr |
|__________|

然后我关闭文件描述符1:

close(1);

文件描述符1转换(指向)内核的Open Files Table中的stdout FILE结构

使用上面的代码,文件描述符1从进程表中删除,该表变为:

 _process1_
|          |
| 0 stdin  |
| 2 stderr |
|__________|

但是内核中会发生什么呢?stdoutFILE结构是否被释放?如果stdout是一个特殊文件(监视器)并且可能被其他进程使用,那怎么可能?只是普通文件(例如.txt)的FILE结构怎么样?如果其他进程正在使用该文件怎么办?

Answers:


13

文件描述符1转换为内核的“打开文件表”中的stdout FILE结构。

这是一个误会。内核的文件表与用户空间文件结构无关。

无论如何,内核都有两个间接级别。有一个内部结构代表文件本身,该文件被引用计数。有一个“打开文件描述”,该引用被计数。然后是文件句柄,该文件句柄不计算引用。文件结构为索引节点本身指明了方向。打开文件描述包含诸如打开模式和文件指针之类的内容。

当您调用关闭时,您总是关闭文件句柄。关闭文件句柄时,其打开的文件描述上的引用计数将减少。如果为零,则打开的文件描述也将释放,并且文件本身的引用计数将减少。仅当该值变为零时,内核的文件结构才会释放。

一个进程没有机会释放另一个进程正在使用的资源,因为共享资源被引用计数。


在您的回答中,我对术语的理解有些困难。我猜该文件指针的意思是“文件偏移量”。这是你的意思吗?您还说文件句柄是什么意思?
极客

正确的是,“文件偏移”是指后续读取或写入将发生的偏移。“文件句柄”是流程和打开的文件描述之间的链接- open成功后您将获得回馈。
David Schwartz 2014年

6

在这种情况下,不会发生很多事情。stdin,stdout和stderr都倾向于是同一文件描述符的克隆。文件描述符的参考计数器将减一。运行该程序的外壳通常包含相同的文件描述符,因此需要保留文件描述符。

内核会保留所有打开的文件(索引)的引用计数。只要引用计数大于零,文件就会被保留。我希望为打开的文件句柄保留一个单独的计数器。一旦达到零,内核就可以释放文件句柄使用的内存。

删除所有对文件的引用(目录条目和文件句柄)后,文件系统代码将标记索引节点以供重用。文件中包含的所有块都可以分配。当释放索引节点时,许多文件系统会清除索引节点中的块指针。这使得恢复已删除的文件很困难。磁盘更新可能会在以后缓冲并完成。


1
两个问题:(1)文件描述符真的被引用计数了吗?当您控制d a时cat > some.file,cat在stdin上获得EOF,而shell没有。(2)为什么引用计数?为什么不进行某种形式的垃圾收集?GC在用户空间上不是更好吗?
Bruce Ediger

扩展BillThor的答案:在正常情况下,stdin,stdout和stderr只是TTY设备的打开文件句柄。因此,如果您关闭文件句柄,则该TTY设备仍然存在,甚至可以在以后再次重新打开。
Patrick

1
@BruceEdiger:(1)当shell运行cat > some.file其实际操作时,是在分支,打开'some.file'并将其分配给文件描述符1,然后它执行exec("cat")。当一个进程被exec()执行时,它继承了打开的文件描述符。
Patrick

@BruceEdiger(2)当引用计数用于不包含指向同一类型其他数据结构的指针(或指向结尾的指针链)的数据结构时,引用计数是一种完美的垃圾回收形式。另外,这是在内核空间中发生的(不是很重要)。
吉尔斯(Gilles)'所以
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.