xv6--一个类Unix的教学用操作系统

第1.3节 管道

2020-10-27  本文已影响0人  橡树人

xv6

第1.3节 管道

这一节中涉及的系统调用有:

一个管道就是一个小型的内核缓冲区,将一对文件描述符暴露给进程:一个用于读,另一个用于写。向管道一端写入的数据可用于另一端读取。
管道提供了一种进程通信的方式。

wc程序的标准输入连接到管道的读取端

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 {
      close(p[0]);
      write(p[1], "hello world\n", 12);
      close(p[1]);
}

解释:

如果没有数据可用,则对管道发起的read调用要么等着写入数据,要么等着所有引用该写入端的文件描述符关闭。

如果是等着所有引用管道写入端的文件描述符关闭,则read调用就返回0,好像到达文件的末尾一样。

在执行程序wc之前,子进程必须要关闭管道的写入端,理由是read会一直阻塞直到不可能有新数据到达为止。

如果程序wc的文件描述符有一个引用指向管道的写入端,则程序wc会永远看不到输入。

xv6实现诸如grep fork sh.c | wc -l这样的流水线的方式跟前面的代码类似,比如:

case PIPE:
    pcmd = (struct pipecmd*)cmd;
    if(pipe(p) < 0)
      panic("pipe");
    if(fork1() == 0){
      close(1);
      dup(p[1]);
      close(p[0]);
      close(p[1]);
      runcmd(pcmd->left);
    }
    if(fork1() == 0){
      close(0);
      dup(p[0]);
      close(p[0]);
      close(p[1]);
      runcmd(pcmd->right);
    }
    close(p[0]);
    close(p[1]);
    wait(0);
    wait(0);
    break;

子进程创建了一个管道连接到一个流水线的右端。

然后,子进程为流水线的左端调用了forkruncmd,为流水线的右端调用了forkruncmd,并等待两者的完成。

流水线的右端可能是一个命令,该命令自身就包含了一个管道,比如a|b|c,该管道自身派生了两个新进程,一个用于b,另一个用于c

因此,shell可能创建一个进程树。树的叶子是命令,内部节点是等待着左右孩子完成的进程。

从理论上讲,可以让内部节点在流水线的左端运行,但是这样会使得流水线的实现变得复杂。

比如,
假设仅做如下修改:修改sh.c不派生子进程用于p>left,而是在内部进程中运行runcmd(p->left)。然后,比如echo hi | wc将不会产生输出,因为echo hi是以runcmd的方式退出的,内部进程退出了,永远不会调用fork派生子进程来运行管道的右端。
这种错误的行为可通过为了内部进程不以rumcmd的方式调用exit来修正,但是这种修复会使代码变得复杂,因为此时runcmd需要判断其是否是一个内部进程。

当没有派生子进程来runcmd(p->right)时,也会增加复杂性。比如,仅做刚才的修改,sleep 10 | echo hi将会立即输出hi,而不是10秒钟以后输出,因为echo立即运行并退出,并没有等待sleep完成。

由于sh.c的目标是尽可能地简单,所以它不会避免创建内部进程。

注:

管道看起来似乎并没有临时文件功能强大,比如流水线

echo hello world | wc

可被实现成没有管道的形式:

echo hello world >/tmp/xyz; wc </tmp/xyz

管道跟临时文件相比,至少有4点优势:

  1. 管道会自动的清理数据。使用了文件重定向,shell要仔细地移除/tmp/xyz
  2. 管道可传递任意长度的数据流,而文件重定向要求磁盘上有足够的空闲空间来存储所有的数据;
  3. 管道允许并行流水线的状态并行执行,但是文件重定向要求:在第二个程序完成前,第一个程序必须完成;
  4. 如果正在实现进程间通信,则管道的阻塞读和阻塞写回被文件的非阻塞语义更有效。
上一篇 下一篇

猜你喜欢

热点阅读