当我 close() 文件描述符时会发生什么?

当我 close() 文件描述符时会发生什么?

我正在尝试使用文件描述符来了解整个情况。假设我有 process1,它最初有这些文件描述符:

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

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

close(1);

文件描述符 1 转换(指向)到标准输出文件结构在内核的打开文件表

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

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

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

答案1

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

这是一个误解。内核的文件表与用户空间文件结构没有任何关系。

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

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

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

答案2

在这种情况下,不会发生太多事情。 stdin、stdout 和 stderr 都倾向于是同一文件描述符的克隆。文件描述符的引用计数器将减一。运行程序的 shell 通常保存相同的文件描述符,因此需要保留文件描述符。

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

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

答案3

您的描述直到最后一段都是正确的。

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

除了内核对 stdin/stdout/stderr 一无所知。这些只是文件描述符 0、1 和 2。这是关于它们用途的约定。

不是最后一段。终端窗口已保存。删除文件描述符并不是删除文件。即使rm只删除目录条目,它也不会删除文件(请参阅其他答案中的引用计数:当没有任何内容引用它时,文件将被删除)。因此,当文件没有目录条目并且不被任何进程打开时,该文件就会被删除。

相关内容