4.7.5 进程通信的实例--管道(pipe)
1.管道pipe
进程通信的使用例子之一是UNIX系统的管道通信。UNIX系统从System V 开始,提供有名管道和无名管道两种通信方式,这里介绍无名管道。
无名管道为建立管道的进程及其子孙提供一条以比特流方式传送消息的通信管道。该管道再逻辑上被看作管道文件,在物理上则由文件系统的高速缓冲区构成,而很少启动外设。发送进程利用文件系统的系统调用write(fd[1],buf,size),把buf种的长度为size字符的消息送入管道入口fd[1],接收进程则使用系统调用read(fd[0],buf,size)从管道出口fd[0]出口读出size字符的消息置入buf中。这里,管道按FIFO(先进先出)方式传送消息,且只能单向传送消息(如图)。
图 管道通信
利用UNIX提供的系统调用pipe,可建立一条同步通信管道。其格式为:
int fd[2];
pipe(fd)
这里,fd[1]为写入端,fd[0]为读出端。
2 .示例
例1:用C语言编写一个程序,建立一个pipe,同时父进程生成一个子进程,子进向pipe中写入一字符串,父进程从pipe中读出该字符串。
解 程序如下:
# include <stdio.h> main() { int x, fd[2]; char buf[30],s[30]; pipe(fd); /*创建管道*/ while((x=fork()) = = -1); /*创建子进程失败时,循环*/ if(x = = 0) { sprintf(buf, ”This is an example\n”); write(fd[1],buf,30); /*把buf中字符写入管道*/ exit(0); } else { wait(0); read(fd[0],s,30); /*父进程读管道中字符*/ printf(“%s”,s); } }
例2:编写一程序,建立一个管道。同时,父进程生成子进程P1,P2,这两个进程分别向管道中写入各自的字符串,父进程读出它们(如图)。
图 父进程和子进程P1,P2通信例子
#include < stdio.h> main( ) { int I,r,p1,p2,fd[2]; char buf[50],s[50]; pipe(fd); /*父进程建立管道*/ while((p1=fork()) = = -1); if(p1 = = 0 ) { lockf(fd[1],1,0); /*加锁锁定写入端*/ sprinrf(buf, ”child process P1 is sending messages! \n”); printf(“child process P1! \n”); write(fd[1],buf, 50); /*把buf中的50个字符写入管道*/ sleep(5); lockf(fd[1],0,0); /*释放管道写入端*/ exit(0); /*关闭P1*/ } else /*从父进程返回,执行父进程*/ { while((p2=fork()) = = -1); /*创建子进程P2,失败时循环*/ if(p2 = = 0) /*从子进程P2返回,执行P2*/ { lockf(fd[1],1,0); / *锁定写入端*/ sprintf(buf, ”child process P2 is sending messages \n”); printf(“child process P2 ! \n”); write(fd[1],buf,50); /*把buf中字符写入管道*/ sleep(5); /* 睡眠等待*/ lockf (fd[1],0,0); /*释放管道写入端*/ exit(0); /*关闭P2*/ } wait(0); if (r = read(fd[0],s 50) = = -1) printf(“can’t read pipe \n”); else printf(“%s\n”,s); wait(0); if(r = read(fd[0],s,50)= = -1) printf(“can’t read pipe \n”); else printf((“%s\n”,s); exit(0); } }
图 例2程序流程图
其中,lockf为保证进程互斥使用管道的系统调用,sleep为保证当前进程睡眠,转让处理机的系统调用。