7

我试图了解在调用 fork() 后复制文件描述符的含义及其对争用的可能影响。

在“Linux 编程接口”24.2.1 (p517) 中:

当执行 fork() 时,子进程接收到所有父文件描述符的副本。这些副本是以 dup() 的方式进行的,这意味着父子节点中对应的描述符引用了相同的打开文件描述。

当我运行相同的代码时:

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/wait.h>

int main(void) {
    char* fl = "/tmp/test_fd";
    int fd;
    fd = open(fl, O_CREAT|O_TRUNC|O_WRONLY, 0666);
    if(!fork()) {
        printf("cfd=%d\n", fd);
        _exit(0);
    } else {
        int status;
        printf("ffd=%d\n", fd);
        wait(&status);
        close(fd);
        unlink(fl);
    }
}

对于两个进程,我得到相同的文件描述符(编号?):ffd=3 和 cfd=3。但是当使用 dup() 运行这段代码时:

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

int main(void) {
    char* fl = "/tmp/test_fd";
    int cfd, ffd;
    ffd = open(fl, O_CREAT|O_TRUNC|O_WRONLY, 0666);
    cfd = dup(ffd);
    printf("ffd=%d\n", ffd);
    printf("cfd=%d\n", cfd);
    close(ffd);
    unlink(fl);
}

我得到不同的文件描述符:ffd=3 和 cfd=4。

然后,我有以下问题:

  1. 什么意味着 fork() 创建了父文件描述符的副本?
  2. 当两个进程(父进程和子进程)在同一个文件描述符上同时执行 fstat() 之类的操作时,是否存在争用?
  3. 如果两个进程同时执行 fstat() 并且两个不同的文件描述符指向同一个文件呢?
4

1 回答 1

16

当您看到短语“复制文件描述符”时,您需要将其理解为“创建一个新的文件描述符,该文件描述符指向另一个指向的相同事物”。

所以当你复制 fd 3 时,你会得到 fd 4。它们不是同一个数字,但它们标识同一个对象。

在 fork 的情况下,您必须记住文件描述符的含义包含在进程中。许多进程都有一个有效的 fd 3,但它们并不都引用同一个对象。使用 fork,你有一个 fd 3 的副本,它也是 fd 3,但在不同的过程中,所以那些 3本质上并不相同;它们是相同的,因为 fork 做了一个副本。

您可以关闭 fd 并在子进程中打开一个不同的文件,您仍然会有两个 fd 3 有效的进程,但它们不再是同一事物的副本。或者你可以让孩子复制 fd 3 以获得 fd 4,然后关闭 fd 3,然后你会在父项中使用 fd 3,在子项中使用 fd 4 来引用同一个对象。

不同进程中的相同数字没有任何意义。

另请注意,文件描述符引用的对象不是文件。在文件描述符和文件之间有一些东西,它被称为打开文件描述。fork 和 dup 都会导致共享打开的打开文件描述。共享的主要后果是当当前文件位置(由and设置lseek或前进)改变时,所有相关的文件描述符都会受到影响,而当标志(如)改变时,所有相关的文件描述符都会受到影响。readwriteO_NONBLOCK

相反,如果你open两次同一个文件,你会得到两个引用同一个文件的文件描述符,但是通过不同的打开文件描述,所以它们有独立的标志和查找位置。

fstat作为一个只读操作,我看不出你在想象什么样的“争用”。

于 2015-05-13T23:27:51.697 回答