コンセプト:バッファパイプラインはカーネルによって管理されている、我々はメモリに一枚の紙と同等のものを置きます。パイプの出力端の接続方法。このプロセスは、パイプラインに情報を入れます。管の他端は、プロセス入力に接続され、プロセス情報は、ダクト内に取り込まれます。
長所:なしロック、バイト指向データ構造が定義されていないする必要はありません
短所:遅い、限られた容量は、狭いシーンを使用して、親と子の間で使用することができます
理論的根拠:
これは、大規模なバッファを必要としない環状構造データであるように設計されているパイプをリサイクルすることができるように、。パイプラインは何も情報がない場合、その情報へのプロセスのもう一方の端まで待つことになるプロセス配管から読み取ります。パイプは情報で満たされると、プロセスアウト情報のもう一方の端まで待機しますプロセスの情報を配置してみてください。二つのプロセスが終了すると、パイプラインは自動的に消えます。
2つのプロセスが同一の管に接続することができるように、原理的には、パイプラインフォーク機構の使用は、確立されています。当初は、上記の二つの矢印は、プロセス工程(二矢印プロセス1に接続された)同じ1に接続されています。フォークコピー処理は、2つの接続は、新しいプロセス(工程2)にコピーされる場合。続いて、プロセスのそれぞれが近いその接続を必要とせず、残りの赤色コネクタを構成するように(2つの黒い矢印は閉じているプロセス1は、パイプへの入力接続から閉鎖され、プロセス2が出力オフパイプに接続されています)上記図のPIPE。
実装の詳細:
Linuxでは、パイプラインの実現は、特殊なデータ構造を使用しますが、iノードinodeファイル構造VFSとファイルシステムによるものではありません。達成物理ページへのターンポイントで2つのファイル構造の同じ一時VFSのinode、inodeのVFSをポイントし、これにより。下記に示すように、
そこ2つのファイルのデータ構造がありますが、それらは、パイプにデータを書き込むためのルーチンのアドレスであるそのうちの一つのルーチンのアドレスが異なっているファイル操作を、定義、およびその他のは、パイプラインからデータを読み込むのルーチンのアドレスです。このように、システムは、ユーザ・プログラムがまだ通常のファイル操作で呼び出し、カーネルは、この特定のパイプライン動作を達成するために、この抽象化メカニズムを利用しています。
読み取りとパイプへの書き込み
管道实现的源代码在fs/pipe.c中,在pipe.c中有很多函数,其中有两个函数比较重要,即管道读函数pipe_read()和管道写函数pipe_wrtie()。管道写函数通过将字节复制到 VFS 索引节点指向的物理内存而写入数据,而管道读函数则通过复制物理内存中的字节而读出数据。当然,内核必须利用一定的机制同步对管道的访问,为此,内核使用了锁、等待队列和信号。
当写进程向管道中写入时,它利用标准的库函数write(),系统根据库函数传递的文件描述符,可找到该文件的 file 结构。file 结构中指定了用来进行写操作的函数(即写入函数)地址,于是,内核调用该函数完成写操作。写入函数在向内存中写入数据之前,必须首先检查 VFS 索引节点中的信息,同时满足如下条件时,才能进行实际的内存复制工作:
·内存中有足够的空间可容纳所有要写入的数据;
·内存没有被读程序锁定。
如果同时满足上述条件,写入函数首先锁定内存,然后从写进程的地址空间中复制数据到内存。否则,写入进程就休眠在 VFS 索引节点的等待队列中,接下来,内核将调用调度程序,而调度程序会选择其他进程运行。写入进程实际处于可中断的等待状态,当内存中有足够的空间可以容纳写入数据,或内存被解锁时,读取进程会唤醒写入进程,这时,写入进程将接收到信号。当数据写入内存之后,内存被解锁,而所有休眠在索引节点的读取进程会被唤醒。
管道的读取过程和写入过程类似。但是,进程可以在没有数据或内存被锁定时立即返回错误信息,而不是阻塞该进程,这依赖于文件或管道的打开模式。反之,进程可以休眠在索引节点的等待队列中等待写入进程写入数据。当所有的进程完成了管道操作之后,管道的索引节点被丢弃,而共享数据页也被释放。
Linux函数原型:
#include <unistd.h> int pipe(int filedes[2]);
filedes[0]用于读出数据,读取时必须关闭写入端,即close(filedes[1]);
filedes[1]用于写入数据,写入时必须关闭读取端,即close(filedes[0])。
程序实例:
int main(void) { int n; int fd[2]; pid_t pid; char line[MAXLINE]; if(pipe(fd) 0){ /* 先建立管道得到一对文件描述符 */ exit(0); } if((pid = fork()) 0) /* 父进程把文件描述符复制给子进程 */ exit(1); else if(pid > 0){ /* 父进程写 */ close(fd[0]); /* 关闭读描述符 */ write(fd[1], "\nhello world\n", 14); } else{ /* 子进程读 */ close(fd[1]); /* 关闭写端 */ n = read(fd[0], line, MAXLINE); write(STDOUT_FILENO, line, n); } exit(0); }