進程通信之(二)進程的管道通信實驗

(二)進程的管道通信實驗

實驗目的

1、瞭解什麼是管道

2、熟悉UNIX/LINUX支持的管道通信方式

 

實驗內容

編寫程序實現進程的管道通信。用系統調用pipe( )建立一管道,二個子進程P1P2分別向管道各寫一句話:

    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( )的進程及其子孫進程才能識別此文件描述符,才能利用該文件(管道)進行通信。當這些進程不再使用此管道時,核心收回其索引結點。

二種管道的讀寫方式是相同的,本文只講無名管道。

3pipe文件的建立

分配磁盤和內存索引結點、爲讀進程分配文件表項、爲寫進程分配文件表項、分配用戶文件描述符

4、讀/寫進程互斥

內核爲地址設置一個讀指針和一個寫指針,按先進先出順序讀、寫。

爲使讀、寫進程互斥地訪問pipe文件,需使各進程互斥地訪問pipe文件索引結點中的直接地址項。因此,每次進程在訪問pipe文件前,都需檢查該索引文件是否已被上鎖。若是,進程便睡眠等待,否則,將其上, 鎖,進行讀/寫。操作結束後解鎖,並喚醒因該索引結點上鎖而睡眠的進程。

三、所涉及的系統調用   

1pipe( )

建立一無名管道。

系統調用格式

              pipe(filedes)

參數定義

int pipe(filedes);

int  filedes[2];

其中,filedes[1]是寫入端,filedes[0]是讀出端。

該函數使用頭文件如下:

#include <unistd.h>

#inlcude <signal.h>

#include <stdio.h>

  2read( )

 系統調用格式

                  read(fd,buf,nbyte)

 功能:從fd所指示的文件中讀出nbyte個字節的數據,並將它們送至由指針buf所指示的緩衝區中。如該文件被加鎖,等待,直到鎖打開爲止。

 參數定義

                  int read(fd,buf,nbyte);

                  int fd;

                  char *buf;

                  unsigned nbyte;

 3write( )

系統調用格式

                  read(fd,buf,nbyte)

功能:把nbyte 個字節的數據,從buf所指向的緩衝區寫到由fd所指向的文件中。如文件加鎖,暫停寫入,直至開鎖。

參數定義同read( )

四、參考程序

#include <unistd.h>

#include <signal.h>

#include <stdio.h>

int pid1,pid2;

 

main( )

   {

int fd[2];

char outpipe[100],inpipe[100];

pipe(fd);                       /*創建一個管道*/

while ((pid1=fork( ))= =-1);

if(pid1= =0)

 {

lockf(fd[1],1,0);

    sprintf(outpipe,"child 1 process is sending message!");

/*把串放入數組outpipe*/

    write(fd[1],outpipe,50);     /*向管道寫長爲50字節的串*/

    sleep(5);                 /*自我阻塞5*/

    lockf(fd[1],0,0);

    exit(0);

           }

else

          {

while((pid2=fork( ))= =-1);

    if(pid2= =0)

{    lockf(fd[1],1,0);           /*互斥*/

   sprintf(outpipe,"child 2 process is sending message!");

                 write(fd[1],outpipe,50);

                 sleep(5);

          lockf(fd[1],0,0);

                 exit(0);

            }

               else

                {  wait(0);              /*同步*/

         read(fd[0],inpipe,50);   /*從管道中讀長爲50字節的串*/

                   printf("%s/n",inpipe);

         wait(0);

         read(fd[0],inpipe,50);

         printf("%s/n",inpipe);

                   exit(0);

               }

        }

}

五、運行結果

   延遲5秒後顯示

child 1 process is sending message!

       再延遲5

              child 2 process is sending message!

六、思考題

1、程序中的sleep(5)起什麼作用?

2、子進程12爲什麼也能對管道進行操作?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章