c - 在 fork() 之后寻求关于 'file descriptor' 的简单描述

标签 c unix fork file-descriptor

在“Unix 环境中的高级编程”中,第 2 版,作者:W. Richard Stevens。 8.3节fork函数。

这是描述:

It is important that the parent and the child share the same file offset.

Consider a process that forks a child, then waits for the child to complete. Assume that both processes write to standard output as part of their normal processing. If the parent has its standard output redirected (by a shell, perhaps) it is essential that the parent's file offset be updated by the child when the child writes to standard output.

我的回复:

{1} 这是什么意思?例如,如果父级的标准输出被重定向到“file1”,那么子级写入后应该更新什么?父级的原始标准输出偏移量或重定向输出(即 file1)偏移量?不会是后者吧?

{2} 更新是如何完成的?由 child 明确地,由操作系统隐式地,由文件描述符本身? fork 之后,我认为 parent 和 child 各奔东西,拥有自己的文件描述符副本。那么child如何更新offset到parent端呢?

In this case, the child can write to standard output while the parent is waiting for it; on completion of the child, the parent can continue writing to standard output, knowing that its output will be appended to whatever the child wrote. If the parent and the child did not share the same file offset, this type of interaction would be more difficult to accomplish and would require explicit actions by the parent.

If both parent and child write to the same descriptor, without any form of synchronization, such as having the parent wait for the child, their output will be intermixed (assuming it's a descriptor that was open before the fork). Although this is possible, it's not the normal mode of operation.

There are two normal cases for handling the descriptors after a fork.

  1. The parent waits for the child to complete. In this case, the parent does not need to do anything with its descriptors. When the child terminates, any of the shared descriptors that the child read from or wrote to will have their file offsets updated accordingly.

  2. Both the parent and the child go their own ways. Here, after the fork, the parent closes the descriptors that it doesn't need, and the child does the same thing. This way, neither interferes with the other's open descriptors. This scenario is often the case with network servers.

我的回复:

{3} 当 fork() 被调用时,我所理解的是 child 得到 parent 拥有的东西的副本,在这种情况下是文件描述符,并做它的事情。如果父子共享的文件描述符的任何偏移量发生变化,那只能是因为描述符记住了偏移量本身。我说得对吗?

我对这些概念有点陌生。

最佳答案

区分文件描述符文件描述很重要,它是进程在其读写调用中用来标识文件的小整数,这是内核中的一个结构。文件偏移量是文件描述的一部分。它存在于内核中。

例如,让我们使用这个程序:

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

int main(void)
{
    int fd;

    fd = open("output", O_CREAT|O_TRUNC|O_WRONLY, 0666);

    if(!fork()) {
        /* child */
        write(fd, "hello ", 6);
        _exit(0);
    } else {
        /* parent */
        int status;

        wait(&status);
        write(fd, "world\n", 6);
    }
}

(已省略所有错误检查)

如果我们编译这个程序,调用它hello,然后像这样运行它:

./hello

这是发生了什么:

程序打开 output 文件,如果它不存在则创建它,如果它存在则将其截断为零大小。内核创建一个文件描述(在 Linux 内核中,这是一个 struct file)并将其与调用进程的文件描述符(该进程的文件中尚未使用的最小非负整数)相关联描述符表)。文件描述符被返回并分配给程序中的fd。为了论证,假设 fd 是 3。

该程序执行一个 fork()。新的子进程获取其父进程的文件描述符表的副本,但文件描述未被复制。两个进程的文件表中的条目号 3 指向相同的 struct file

父进程等待,子进程写入。 child的写入导致"hello world\n"的前半部分存入文件,并将文件偏移量前移6。文件偏移量在struct file!

子进程退出,父进程的 wait() 完成,父进程写入,使用 fd 3,它仍然与相同的文件描述相关联,其文件偏移由子进程的 更新写()。所以消息的后半部分存储在第一部分之后,而不是像父文件偏移量为零时那样覆盖它,如果文件描述不是分享。

最后父级退出,内核发现 struct file 不再使用并释放它。

关于c - 在 fork() 之后寻求关于 'file descriptor' 的简单描述,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11733481/

相关文章:

unix - 在一个进程中关闭所有打开的文件

c - accept() 返回相同的套接字描述符编号

c - fork()后调用exec()会不会导致现有进程数据丢失

c - 我是否发现了 libxml2 错误(多线程解析中的内存泄漏)?

c - 如何确定文件描述符是否附加到 Linux 中的文件或套接字

java - 原子文件修改

unix - 使用 fork 和 sockets 时处理不正常的关闭

检查 C/*nix 中指定用户的文件访问权限

c - 数组删除用户输入值的所有元素

c - 在 while 循环中使用 scanf 的问题