實驗內容
編寫程序實現進程的管道通信。用系統調用pipe( )建立一管道,二個子進程P1和P2分別向管道各寫一句話:
Child 1 is sending a message!
Child 2 is sending a message!
父進程從管道中讀出二個來自子進程的信息並顯示(要求先接收P1,後P2)。
實驗指導
一、什麼是管道
UNIX系統在OS的發展上,最重要的貢獻之一便是該系統首創了管道(pipe)。這也是UNIX系統的一大特色。
所謂管道,是指能夠連接一個寫進程和一個讀進程的、並允許它們以生產者—消費者方式進行通信的一個共享文件,又稱為pipe文件。由寫進程從管道的寫入端(句柄1)將數據寫入管道,而讀進程則從管道的讀出端(句柄0)讀出數據。
句柄fd[0]
句柄fd[1]
讀出端
寫入端
二、管道的類型:
1、有名管道
一個可以在文件系統中長期存在的、具有路徑名的文件。用系統調用mknod( )建立。它克服無名管道使用上的局限性,可讓更多的進程也能利用管道進行通信。因而其它進程可以知道它的存在,並能利用路徑名來訪問該文件。對有名管道的訪問方式與訪問其他文件一樣,需先用open( )打開。
2、無名管道
一個臨時文件。利用pipe( )建立起來的無名文件(無路徑名)。只用該系統調用所返回的文件描述符來標識該文件,故只有調用pipe( )的進程及其子孫進程才能識別此文件描述符,才能利用該文件(管道)進行通信。當這些進程不再使用此管道時,核心收回其索引結點。
二種管道的讀寫方式是相同的,本文只講無名管道。
3、pipe文件的建立
分配磁盤和內存索引結點、為讀進程分配文件表項、為寫進程分配文件表項、分配用戶文件描述符
4、讀/寫進程互斥
內核為地址設置一個讀指針和一個寫指針,按先進先出順序讀、寫。
為使讀、寫進程互斥地訪問pipe文件,需使各進程互斥地訪問pipe文件索引結點中的直接地址項。因此,每次進程在訪問pipe文件前,都需檢查該索引文件是否已被上鎖。若是,進程便睡眠等待,否則,將其上鎖,進行讀/寫。操作結束後解鎖,並喚醒因該索引結點上鎖而睡眠的進程。
三、所涉及的系統調用
1、pipe( )
建立一無名管道。
系統調用格式
pipe(filedes)
參數定義
int pipe(filedes);
int filedes[2];
其中,filedes[1]是寫入端,filedes[0]是讀出端。
該函數使用頭文件如下:
#include <unistd.h>
#inlcude <signal.h>
#include <stdio.h>
2、read( )
系統調用格式
read(fd,buf,nbyte)
功能:從fd所指示的文件中讀出nbyte個字節的數據,並將它們送至由指針buf所指示的緩沖區中。如該文件被加鎖,等待,直到鎖打開為止。
參數定義
int read(fd,buf,nbyte);
int fd;
char *buf;
unsigned nbyte;
3、write( )
系統調用格式
read(fd,buf,nbyte)
功能:把nbyte 個字節的數據,從buf所指向的緩沖區寫到由fd所指向的文件中。如文件加鎖,暫停寫入,直至開鎖。
參數定義同read( )。
〈任務〉
編制一段程序,實現進程的管道通信。使用系統調用pipe()建立一條管道線。兩個子進程p1和p2分別向通道個寫一句話:
child1 process is sending message!
child2 process is sending message!
而父進程則從管道中讀出來自兩個進程的信息,顯示在屏幕上。
程序一:
#include<unistd.h> #include<sys/types.h> #include<errno.h> #include<stdio.h> #include<stdlib.h> #include<string.h> int main() { int pipe_fd[2]; pid_t pid; char buf_r[100]; char* p_wbuf; int r_num; memset(buf_r,0,sizeof(buf_r)); if(pipe(pipe_fd)<0){ printf("pipe create error\n"); return -1; } if((pid=fork())==0) { printf("\n"); close(pipe_fd[1]); sleep(2); if((r_num=read(pipe_fd[0],buf_r,100))>0){ printf("%d numbers read from the pipe is %s\n",r_num,buf_r); } close(pipe_fd[0]); exit(0); } else if(pid>0) { close(pipe_fd[0]); if(write(pipe_fd[1],"Hello",5)!=-1) printf("parent writel success!\n"); if(write(pipe_fd[1],"pipe",5)!=-1) printf("parent write2 success!\n"); close(pipe_fd[1]); sleep(3); waitpid(pid,NULL,0); exit(0); } }