我无法理解 xv6 中的管道及其实现

我无法理解 xv6 中的管道及其实现

我正在通过在线 MOOC 讲座自学操作系统,并想研究 xv6。我正在阅读 xv6 的文档,在第 0 章中谈到管道(第 13 页),我对此产生了怀疑。

int p[2];
char *argv[2];
argv[0] = "wc";
argv[1] = 0;

pipe(p);
if(fork()==0){
close(0);
dup(p[0]);
close(p[0]);
close(p[1]);
exec("/bin/wc", argv);
}
else{
write(p[1], "hello world\n", 12);
close(p[0]);
close(p[1]);}

内容如下:-
现在,子进程将读取端复制到文件描述符 0 上,关闭 p 中的 fds,并执行 wc。当 wc 从其标准输入读取时,它会从管道读取。父进程写入管道的写入端,然后关闭其两个文件描述符。

另外,需要提到的是,各个过程不共享变量,即一个过程中所做的更改不会反映在另一个过程中。

现在,我在这里向父进程写入,如果子进程在父进程完成写入 p[1] 之前到达 exec,子进程将等待,在完成写入后,子进程将从 p[0] 读取并执行 exec。那么,管道具有特殊权限,这使得它们通过共享管道支持进程间通信,这种说法正确吗?那么,与变量(其更改不会反映在其他进程中)不同,管道是共享的,因此它们的更改会相互反映?
上述推理正确吗?

答案1

您的推理基本正确。但这并不是说管道具有特殊权限;您只是把它们看错了。管道不是变量,而是使用系统调用在内核中创建的 OS 对象pipe,可以同时在一个或多个进程中打开。写入管道可写端的数据(即在调用中创建pipe(p)并存储在数组中的两个文件描述符中的第二个p)可在另一个文件描述符中读取(p[0]此处,然后复制到文件描述符 0,即用于的文件描述符stdin)。无论哪些进程打开了这些文件描述符,都可以从管道读取和写入。

您可能会注意到,您不只是为管道分配值;您write还像文件一样为它们分配值(并且write是系统调用;程序告诉内核执行某些操作,而不仅仅是更改其本地内存中的值)。事实上,如果您将管道视为类似文件,除了它们可以是匿名的(未命名的)、不能具有能够读写的文件描述符(即它们是单向的)并且仅在写入和读取之间保存数据,而不是在读取数据或关闭管道的所有文件描述符后保存数据,那么您就不会错。就像两个进程可以共享对同一文件的访问权限一样,两个进程也可以共享对管道的访问权限(此处显示的方式是创建两个进程共享的管道的常用方法,但您也可以让两个完全不相关的进程打开一个“命名管道”,这与文件的想法相同,只是您给它一个像文件一样的名称,并且每个进程一次打开一端并指定它是想要读取端还是写入端)。

手动创建管道通常用于进程间通信,但不一定在源代码中。另外,两个程序不需要同时运行。如果您在 shell 中使用|(“管道字符”)写入一行,则告诉 shell 创建一个从stdout第一个命令的 到stdin第二个命令的 的管道(非常类似于您上面的示例创建一个到 的 的管道stdin/bin/wc。也就是说,shell 命令(如ls | wc)创建一个管道,将可写端设置为文件描述符 1(stdout),执行ls并因此在该管道中捕获其输出,然后将可读端设置为文件描述符 0(stdin)并执行wc,它会及时读取现已完成的输出ls并将结果输出到它自己的stdout,最终到达您的终端。

相关内容