Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 寻求有关'的简单描述;文件描述符';在fork()之后_C_Unix_Fork_File Descriptor - Fatal编程技术网

C 寻求有关'的简单描述;文件描述符';在fork()之后

C 寻求有关'的简单描述;文件描述符';在fork()之后,c,unix,fork,file-descriptor,C,Unix,Fork,File Descriptor,在“Unix环境中的高级编程”第二版中,作者:W.Richard Stevens。第8.3节分叉功能 以下是描述: 父级和子级共享相同的文件偏移量非常重要 考虑一个分叉子进程,然后等待子进程完成。假设两个进程都将写入标准输出作为其正常处理的一部分。如果父对象的标准输出被重定向(可能是通过shell重定向),则当子对象写入标准输出时,子对象必须更新父对象的文件偏移量 我的答复是: {1} 这是什么意思?例如,如果父级的std输出被重定向到“file1”,那么在子级写入之后,子级应该更新什么?父级原

在“Unix环境中的高级编程”第二版中,作者:W.Richard Stevens。第8.3节分叉功能

以下是描述:

父级和子级共享相同的文件偏移量非常重要

考虑一个分叉子进程,然后等待子进程完成。假设两个进程都将写入标准输出作为其正常处理的一部分。如果父对象的标准输出被重定向(可能是通过shell重定向),则当子对象写入标准输出时,子对象必须更新父对象的文件偏移量

我的答复是:

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

{2} 更新是如何完成的?通过子显式,通过操作系统隐式,通过文件描述符本身?在fork之后,我认为父级和子级各走各的路,拥有自己的文件描述符副本。那么,子更新如何偏移到父端呢

在这种情况下,子级可以在父级等待时写入标准输出;完成子级后,父级可以继续写入标准输出,知道其输出将附加到子级写入的任何内容。如果父级和子级不共享相同的文件偏移量,则这种类型的交互将更难完成,并且需要父级执行显式操作

如果父级和子级都写入同一个描述符,而没有任何形式的同步,例如让父级等待子级,那么它们的输出将是混合的(假设它是在fork之前打开的描述符)。虽然这是可能的,但这不是正常的操作模式

在fork之后处理描述符有两种常见情况

  • 父对象等待子对象完成。在这种情况下,父对象不需要对其描述符执行任何操作。当子项终止时,子项读取或写入的任何共享描述符都将相应地更新其文件偏移量

  • 父母和孩子各走各的路。在这里,在fork之后,父对象关闭它不需要的描述符,子对象做同样的事情。这样,两者都不会干扰对方的开放描述符。网络服务器通常就是这种情况

  • 我的答复是:

    {3} 当调用fork()时,我所理解的是,child获取父级所拥有的文件描述符的副本,并执行它的操作。如果父级和子级共享的文件描述符的任何偏移量发生更改,这只能是因为描述符记住了偏移量本身。我说得对吗


    我对这些概念有点陌生。

    区分文件描述符文件描述很重要,前者是进程在读写调用中用来标识文件的小整数,后者是内核中的一种结构。文件偏移量是文件描述的一部分。它生活在内核中

    例如,让我们使用以下程序:

    #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);
        }
    }
    
    下面是发生的情况:

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


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

    父进程等待子进程写入。孩子的写入会导致文件中存储
    “hello world\n”
    的前半部分,并将文件偏移量提前6。文件偏移量在结构文件中

    子级退出,父级的
    wait()
    完成,父级使用fd 3写入,fd 3仍然与子级的
    write()
    更新了其文件偏移量的同一文件描述相关联。因此,消息的后半部分存储在第一部分之后,不会像父部分的文件偏移量为零时那样覆盖它,如果文件描述未共享,则会发生这种情况


    最后,父级退出,内核看到结构文件不再使用并将其释放。

    在本书的同一部分中,有一个图表显示了打开文件时存在的三个表

    用户filedescriptor表(流程表条目的一部分)、filetable和inode表(v节点表)。 现在,filedescriptor(文件描述符表的索引)条目指向一个文件表条目,该条目指向一个inode表条目。
    现在文件偏移量(下一次读/写发生的位置)在文件表中。

    假设您在父级中打开了一个文件,这意味着它有一个描述符,一个文件 表条目和索引节点引用。
    现在,当您创建一个子文件时,会为该子文件复制文件描述符表。
    因此,文件表条目中的引用计数(对于打开的描述符)增加,这意味着现在同一文件表条目有两个引用

    此描述符现在在父级和子级中都可用,指向相同的文件表条目,因此共享偏移量。 现在有了这个背景,让我们看看你的问题
    ./hello
    
     Parent ( )
      {
        open a file for writing, that is get the 
        descriptor( say fd);
        close(1);//Closing stdout
        dup(fd); //Now writing to stdout  means writing to the file
        close(fd)
            //Create a child that is do a  fork call.
        ret = fork();
        if ( 0 == ret )
        {
            write(1, "Child", strlen("Child");
            exit ..
        }
            wait(); //Parent waits till child exit.
    
             write(1, "Parent", strlen("Parent");
        exit ..
    }
    
    Now I think the answer is clear-> by the system call that is by the OS.