use*_*625 33 c unix fork file-descriptor
在"Unix环境中的高级编程",第2版,作者:W.Richard Stevens.
第8.3节fork函数.
这是描述:
父和子共享相同的文件偏移量很重要.
考虑一个分叉孩子的过程,然后等待孩子完成.假设两个进程都写入标准输出作为其正常处理的一部分.如果父级的标准输出重定向(可能是shell),则当子级写入标准输出时,子级必须更新父级的文件偏移量.
[1.这是什么意思?例如,如果父项的std输出被重定向到'file1',那么子项写入后子项应该更新什么?parent的原始std输出偏移量或重定向输出(即file1)偏移量?不能晚了,对吧?
[2.更新是如何完成的?由子显式,由OS隐式地,由文件描述符本身?在fork之后,我认为父母和孩子走自己的路,并拥有自己的文件描述符COPY.那么孩子如何更新偏移到父方?]
在这种情况下,孩子可以在父母等待时写入标准输出; 在孩子完成后,父母可以继续写入标准输出,知道其输出将附加到孩子写的任何内容.如果父级和子级没有共享相同的文件偏移量,则此类交互将更难以完成,并且需要父级的显式操作.
如果父节点和子节点都写入相同的描述符,而没有任何形式的同步,例如让父节点等待子节点,则它们的输出将被混合(假设它是在fork之前打开的描述符).虽然这是可能的,但这不是正常的操作模式.
在fork之后处理描述符有两种正常情况.
父母等待孩子完成.在这种情况下,父级不需要对其描述符执行任何操作.当子进程终止时,子进程读取或写入的任何共享描述符将相应地更新其文件偏移量.
父母和孩子都有自己的方式.这里,在fork之后,父关闭它不需要的描述符,并且子进行相同的操作.这样,既不会干扰对方的开放描述符.网络服务器经常出现这种情况."
[3.当调用fork()时,我理解的是那个子得到了父有什么的COPY,在这种情况下是文件描述符,并做了它的事情.如果任何偏移更改为父和子共享的文件描述符,则只能因为描述符记住偏移本身.我对吗?]
对不起,我对这些概念不太了解.
有帮助吗?谢谢.
Ala*_*rry 79
它的区别是很重要的文件描述符,这是该进程在其读取和写入调用用来标识文件小的整数,文件描述,这是在内核的结构.文件偏移量是文件描述的一部分.它存在于内核中.
举个例子,让我们使用这个程序:
#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);
}
}
Run Code Online (Sandbox Code Playgroud)
(省略了所有错误检查)
如果我们编译这个程序,请调用它hello,并像这样运行它:
./hello
Run Code Online (Sandbox Code Playgroud)
这是发生了什么:
程序打开output文件,如果它不存在则创建它,或者如果它确实存在则将其截断为零大小.内核创建一个文件描述(在Linux内核中这是一个struct file)并将其与调用进程的文件描述符相关联(该进程的文件描述符表中尚未使用的最低非负整数).返回文件描述符并fd在程序中分配.为了论证,假设fd是3.
该程序执行fork().新的子进程获取其父级文件描述符表的副本,但不复制文件描述.两个进程的文件表中的条目号3指向相同的struct file.
父进程在子进程写入时等待.孩子的写入导致前半部分"hello world\n"存储在文件中,并使文件偏移量增加6.文件偏移量在struct file!
子进程退出,父wait()进程完成,父进程使用fd 3进行写入,fd 3仍然与相同的文件描述相关联,文件描述的文件偏移由子进程更新write().因此,消息的第二半被存储后的第一部分,而不是覆盖它,因为它会做如果父有文件的零点偏移,如果文件的描述是不共享这将是这种情况.
最后,父进程退出,内核看到它struct file已不再使用并释放它.
在本书的同一部分,有一个图表显示了打开文件时存在的三个表。
用户文件描述符表(进程表条目的一部分)、文件表和inode 表(v-node 表)。现在一个文件描述符(它是文件描述符表的索引)条目指向一个文件表条目,它指向一个 inode 表条目。
现在文件偏移量(下一次读/写发生的位置)在 文件表中。
因此,假设您在父级中打开了一个文件,这意味着它也有一个描述符、一个文件表条目和一个 inode 引用。
现在,当您创建子项时,会为子项复制文件描述符表。所以文件表条目中的引用计数(对于那个打开的描述符)增加了,这意味着现在同一个文件表条目有两个引用。
这个描述符现在在父级和子级中都可用,指向同一个文件表条目,因此共享偏移量。 现在有了这个背景,让我们看看你的问题,
孩子明确不需要更新任何东西。这本书的作者试图
说明这一点,假设父母的标准输出被重定向到一个文件并进行了 fork 调用。之后父级正在等待。所以现在描述符被复制,即文件偏移量也被共享。现在每当孩子向标准输出写入任何内容时,写入的数据都会保存在重定向文件中。
偏移量通过写入调用自动增加。
现在说孩子退出。所以父级从等待中出来并在标准输出(被重定向)上写了一些东西。现在 parent 的 write 调用的输出将被放置 -> 在孩子写入的数据之后。为什么 -> 因为偏移量的当前值现在在孩子写入后发生了变化。
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 ..
}
Run Code Online (Sandbox Code Playgroud)
Pl。看上面的伪代码,打开的文件最终包含的数据是ChildParent。因此,您会看到文件偏移量在子项写入时发生了更改,并且这对于父项的写入调用是可用的,因为该偏移量是共享的。
2.更新是如何完成的?由子显式,由操作系统隐式,由文件描述符本身?在 fork 之后,我认为父母和孩子各行其是,并拥有自己的文件描述符 COPY。那么子级如何更新对父级的偏移量?]
Now I think the answer is clear-> by the system call that is by the OS.
Run Code Online (Sandbox Code Playgroud)
[3. 当 fork() 被调用时,我所理解的是孩子得到了父母拥有的东西的副本,在这种情况下是文件描述符,并做它的事情。如果父子进程共享的文件描述符有任何偏移量发生变化,那只能是因为描述符记住了偏移量本身。我对吗?]
这也应该清楚。用户文件表项指向文件表表项(包含偏移量)。
换句话说,系统调用可以从描述符中获取偏移量。