调用dup/dup2后关闭文件描述符的规则是什么?

What are the rules of closing file descriptors after calling dup/dup2?

我觉得这是我为 g运行ted 选的主题。在过去,我实际上只是关闭了尽可能多的文件描述符 "because I was told to"。大多数时候这是有效的,但偶尔我 运行 会出现一些不可预知的行为。

因此,我想问一下 - 调用 dup / dup2 后关闭文件描述符的规则是什么?

假设我要执行 cat < in > out

fd[IN] = open("in", O_RDONLY);
saved_stdin = dup(STDIN_FILENO);
dup2(fd[IN], STDIN_FILENO);
close(fd[IN])

fd[OUT] = open("out", O_WRONLY | O_CREAT | O_TRUNC, 0644);
saved_stdout = dup(STDOUT_FILENO);
dup2(fd[OUT], STDOUT_FILENO);
close(fd[OUT])


// Later on when I want to restore stdin and stdout
dup2(saved_stdin, STDIN_FILENO);
close(saved_stdin);
dup2(saved_stdout, STDINOUT_FILENO);
close(saved_stdout);

这是正确的还是我应该关闭更多文件描述符?

规则确实很简单。对于两个 dup() 变体,确实如此:

  • 源 fd 保持打开状态,一旦不再需要就必须将其关闭。

  • 目标文件描述符,

    • 使用 dup() 时,始终是未使用的
    • 当使用 dup2() 时,隐式关闭并替换为源 fd 的副本。
  • 新的目标 fd 在不再需要时必须关闭。

Source fd是指要复制的文件描述符,target fd是新的文件描述符。

int new_fd = dup(source_fd);
dup2(source_fd, new_fd);

所以是的,您的代码执行必要的关闭操作,没有不需要的关闭操作。

数据来自CSAPP系统级:

Figure 2: Before Redirect IO

dup2(4,1);

Figure 1: After Redirect IO

注意 fd 1refcnt 在调用 dup2 后变为 0。

根据linux manualclose的描述。它说:

if the file descriptor was the last reference to a file which has been removed using unlink(2), the file is deleted.

close用于减少打开文件的refcnt。我们使用 dup 创建一个新的 fd 将增加打开文件的 refcnt。当我们调用 close 函数时,它并没有立即关闭文件,它只是减少了文件的引用计数。当 refcnt 为 0 时,文件将为 close/delete。

所以它真的很像内存管理的引用计数。