⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 00000014.htm

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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -