fork()后相同的文件描述符

8
我正在尝试理解在调用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()时会怎样?

这个相关的问题可能会有所帮助:https://dev59.com/WWgt5IYBdhLWcg3w5xc_#11734354 - Diego
1个回答

18
当你看到“复制文件描述符”这个短语时,你需要理解它为“创建一个新的文件描述符,它指向另一个指向同一物体的文件描述符”。
所以当你复制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都会导致一个打开的文件描述符被共享。共享的主要影响是当当前文件位置(由lseek设置或由read和write推进)发生变化时,所有相关的文件描述符都会受到影响;当标志(如O_NONBLOCK)发生变化时,所有相关的文件描述符也会受到影响。
相比之下,如果你以两种不同的方式打开同一个文件,你会得到两个文件描述符,它们指向同一个文件,但通过不同的打开文件描述符,因此它们具有独立的标志和寻找位置。
由于fstat是只读操作,我不明白你所想象的"争用"是什么样的。

感谢清晰的解释,我没有考虑到文件描述符的编号是针对进程本地的。 - omx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接