📄 00000014.htm
字号:
<HTML><HEAD> <TITLE>BBS水木清华站∶精华区</TITLE></HEAD><BODY><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER>发信人: SuperSB (孤鹰), 信区: Linux <BR>标 题: [转载]unix环境高级编程-14 <BR>发信站: BBS 水木清华站 (Wed Mar 15 14:31:10 2000) <BR> <BR> <BR> <BR> <BR>发信人: taosm (128+64-->cool), 信区: unix <BR>标 题: unix环境高级编程--第14章 进程间通信 <BR>发信站: 西十八BBS (Sat Mar 11 13:57:20 2000), 转信 <BR> <BR> <BR>第十四章; 进程间通信 <BR>14.1 介绍 <BR>在第八章中,我们说明了进程控制原语并且观察了如何调用多个进程。但是这些进 <BR>程之间交换信息的唯一方法是经由fork或exec传送打开文件,或通过文件系统。现 <BR>在,我们说明进程之间相互通信的其它技术-IPC(interprocess communication) <BR>。 <BR>Unix IPC已经是而且继续是各种进程通信方式的统称,其中极少能在所有Unix的实 <BR>现中进行移植。图14.1摘要列出了不同实现所支持的不同形式的IPC。 <BR>图14.1 UNIX IPC 摘要 <BR>正如上图所示,不管哪一种Unix实现,我们都可依靠的唯一一种IPC是半双工的管 <BR>道(pipes)。图中前7种IPC通常限于同一台主机的各个进程间的IPC。最后二种; <BR>套接口和流,是支持不同主机上各个进程间IPC。(关于网络IPC的详细情况,请参 <BR>见Stevens[1990]。)虽然中间三种形式的IPC(消息队列、信号量以及共享存储器 <BR>)在图中说明为只受到系统V的支持,但是在大多数制造商所支持的,从贝克莱Un <BR>ix导出的Unix系统中(例如,SunOS以及Ultrix),已经添加了这三种形式的IPC。 <BR> <BR> 几个Posix小组正在对IPC进行工作,但是最后结果还不很清楚,在1994年 <BR>甚至 <BR> 更迟一点与IPC有关的Posix可能还不会制定出来。 <BR>我们已将与IPC有关的讨论分成两章。在本章中,我们讨论经典的IPC;管道、FIF <BR>O、消息队列、信号量以及共享存储器。在下一章中,我们将观察SVR4和4.3+BSD共 <BR>同支持的IPC的某些高级特征,包括;流管道和命名的流管道,以及用这些更高级 <BR>形式IPC,我们可以做的一些事情。 <BR>14.2 管道 <BR>管道是Unix IPC的最老形式,并且所有Unix系统都提供此种通信机制,管道有两种 <BR>限制; <BR>1. 它们是半双工的。数据只在一个方向流动。 <BR>2. 它们只能在具有公共祖先的进程之间使用。通常,一个管道由一个进程创建, <BR>然后该进程调用fork,此后父、子进程之间就可应用该管道。 <BR>我们将会看到流管道(15.2节)没有第一种限制,FIFO(14.5节)和命名流管道( <BR>15.5节)则没有第二种限制。尽管有这两种限制,半双工管道仍是最常用的IPC形 <BR>式。 <BR> 管道是由调用pipe函数而创建的。 <BR> #include <unistd.h> <BR> int pipe(int filedes[2]) ; <BR>返回:若成功为0,出错为-1 <BR>经由参数filedes返回两个文件描述符;filedes[0]是为读而打开,filedes[1]是 <BR>为写而打开的。filedes[1]的输出是filedes[0]的输入。 <BR>有两种方法来描画一个管道,如图14.2中所示。左半图显示了管道的两端在一个进 <BR>甚至 <BR> 更迟一点与IPC有关的Posix可能还不会制定出来。 <BR>我们已将与IPC有关的讨论分成两章。在本章中,我们讨论经典的IPC;管道、FIF <BR>O、消息队列、信号量以及共享存储器。在下一章中,我们将观察SVR4和4.3+BSD共 <BR>同支持的IPC的某些高级特征,包括;流管道和命名的流管道,以及用这些更高级 <BR>形式IPC,我们可以做的一些事情。 <BR>14.2 管道 <BR>管道是Unix IPC的最老形式,并且所有Unix系统都提供此种通信机制,管道有两种 <BR>限制; <BR>1. 它们是半双工的。数据只在一个方向流动。 <BR>2. 它们只能在具有公共祖先的进程之间使用。通常,一个管道由一个进程创建, <BR>然后该进程调用fork,此后父、子进程之间就可应用该管道。 <BR>我们将会看到流管道(15.2节)没有第一种限制,FIFO(14.5节)和命名流管道( <BR>15.5节)则没有第二种限制。尽管有这两种限制,半双工管道仍是最常用的IPC形 <BR>式。 <BR> 管道是由调用pipe函数而创建的。 <BR> #include <unistd.h> <BR> int pipe(int filedes[2]) ; <BR>返回:若成功为0,出错为-1 <BR>经由参数filedes返回两个文件描述符;filedes[0]是为读而打开,filedes[1]是 <BR>为写而打开的。filedes[1]的输出是filedes[0]的输入。 <BR>有两种方法来描画一个管道,如图14.2中所示。左半图显示了管道的两端在一个进 <BR>图14.4 从父进程到子进程的管道 <BR>对于从子进程到父进程的管道,父进程关闭 fd[1],子进程关闭fd[0]。 <BR>当管道的一端被关闭后,下列规定起作用; <BR>1. 当读一个写端已被关闭的管道时,在所有数据都被读取后,read返回0,以指示 <BR>达到了文件结束处。(从技术方面考虑,在管道的写端还有进程时,就不会产生文 <BR>件的结束。可以复制一个管道的描述符,使得有多个进程具有写打开文件描述符。 <BR>但是,通常一个管道只有一个读进程,一个写进程。在下一节介绍FIFO时,我们会 <BR>看到对于一个单一的FIFO常常有多个写进程)。 <BR>2. 如果写一个读端已被关闭的管道,则产生信号SIGPIPE。如果忽略该信号或者捕 <BR>捉该信号并从其处理程序返回,则Write出错返回,errno设置为EPIPE。 <BR>在写管道时,常数PIPE_BUF规定了核中管道缓存器的大小。如果对管道进行write <BR>调用,而且要求写的字节数小于等于PIPE_BUF,则此操作不会与其它进程对同一管 <BR>道(或FIFO)的write操作穿插进行。但是,若有多个进程同时写一个管道(或FI <BR>FO),而且某个或某些进程要求写的字节数超过PIPE_BUF字节数,则数据可能会与 <BR>其它写操作的数据相穿插。 <BR>实例 <BR> 程序14.1中创建了一个从父进程到子进程的管道,并且父进程经由该管道向子 <BR>进程传送数据。 <BR>#include "ourhdr.h" <BR>int <BR>main(void) <BR>{ <BR> int n, fd[2]; <BR> pid_t pid; <BR> char line[MAXLINE]; <BR> if (pipe(fd) < 0) <BR> err_sys("pipe error"); <BR> if ( (pid = fork()) < 0) <BR> err_sys("fork error"); <BR> else if (pid > 0) { /* parent */ <BR> close(fd[0]); <BR> write(fd[1], "hello world\n", 12); <BR> } else { /* child */ <BR> close(fd[1]); <BR> n = read(fd[0], line, MAXLINE); <BR> write(STDOUT_FILENO, line, n); <BR> } <BR> exit(0); <BR>} <BR>程序14.1 经由管道父进程向子进程传送数据 <BR>在上面的例子中,我们直接对管道描述符调用read和write。更为有益的是将管道 <BR>描述符复制为标准输入和标准输出。在此之后通常子进程调用exec,执行另一道程 <BR>序,开从标准输入(已创建的管道)或将数据写至其标准输出(管道)。 <BR>实例 <BR>让我们编写一道程序,其功能是每次一页显示已产生的输出。已经有很多Unix公用 <BR>程序具有分页功能,因此我们无需再构造一个新的分页程序,而是调用用户最喜爱 <BR>的分页程序。为了避免先将所有数据写到一个临时文件中,然后再调用系统中有关 <BR>程序显示该文件,我们希望将输出通过管道直接送到分页程序。为此,先创建一个 <BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -