進程間通信之管道通信(匿名管道)

  Linux中,每個進程都有各自的地址空間及自己的用戶級頁表,映射到物理內存的不同地方,因此進程間互不影響,即進程間相互獨立。

那麼不同的進程要如何實現進程間通信呢?也就是進程間通信的本質,就是不同的進程通過看到公共資源來實現進程間通信,而這裏的公共資源一般由操作系統提供,不同的提供者、提供方式也決定了通信方式的不同。
進程間有五中通信方式,分別爲:匿名管道、命名管道、信號量、消息隊列、共享內存。這裏先介紹一下匿名管道通信。
匿名管道(pipe)
函數:int pipe(int pipefd[2]);
注:調用pipe函數時,首先在內核中開闢一塊緩衝區用於通信,它有一個讀端和一個寫端,然後通過pipefd參數傳出給用戶進程兩個文件描述符,pipefd[0]指向管道的讀端,pipefd[1]指向管道的寫段。在用戶層面看來,打開管道就是打開了一個文件,通過read()或者write()向文件內讀寫數據,讀寫數據的實質也就是往內核緩衝區讀寫數據。

返回值:成功返回0,失敗返回-1。

管道特徵:
1、管道只支持單向通信
2、管道通信只能用於有血緣關係的通信,常用於父子通信,只用於父子進程的管道(匿名管道)
3、管道的生命週期隨進程的結束而終止
4、管道是基於字節流通信的通信方式
5、管道內部已經實現同步機制,能夠保證數據一致性(保證數據的安全性,在寫數據的時候不會被別人讀,不會發生二義性)

實現進程通信步驟:
1、父進程調用pipe開闢管道,得到兩個文件描述符指向管道的兩端
2、父進程調用fork創建子進程,子進程也有兩個文件描述符指向管道的兩端
3、父進程關閉fd[0](讀端),子進程關閉fd[1](寫端)

例:

#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<string.h>
int main()
{
    int fds[2];
    if(pipe(fds)<0)
    {
        perror("pipe");
        return 1;
    }
    pid_t id=fork();//fork創建子進程
    if(id==0)
    {
        //child
        close(fds[0]);//子進程關閉讀端
        const char* child="hello father,I'm child";
        int i=0;
        while(i<10)
        {
            sleep(1);
            write(fds[1],child,strlen(child));
            i++;
        }
        exit(0);
    }
    else
    {
        //father
        close(fds[1]); //父進程關閉寫端
        char buf[1024];
        while(1)
        {
            ssize_t s=read(fds[0],buf,sizeof(buf)-1);
            if(s>0)
            {
                buf[s]=0;
                printf("father received:%s\n",buf);
            }
        }
    }
    pid_t ret=waitpid(id,NULL,0);
    if(ret>0)
    {
        printf("wait success!\n");
    }
}

運行結果:
這裏寫圖片描述
父進程成功收到子進程寫入的字符串。

使用管道時有4種特殊情況:
1、讀端沒關閉,讀端沒有讀數據,寫端在寫數據,管道被寫滿時寫會阻塞,直到有空了才寫入數據返回(讀端沒有在讀,寫端一直在寫)

代碼驗證:
這裏寫圖片描述

運行結果:
這裏寫圖片描述
父進程執行3次讀操作後不再讀取數據,而子進程一直在在寫,管道寫滿時發生阻塞。

2、指向管道的進程描述符的寫端沒關閉,持有管道寫端的進程沒有向管道寫數據,此時有進程從管道讀端讀數據,管道剩餘數據讀取後,再次read會阻塞,知道有數據可讀纔讀取數據返回(讀方一直在讀,寫方沒有在寫)

代碼驗證:
這裏寫圖片描述
運行結果:
這裏寫圖片描述
3、管道讀端的文件描述符都關閉了,此時向管道的寫端寫,進程會收到信號SIGPIPE,通常導致進程異常終止
代碼驗證:
這裏寫圖片描述
運行結果:
這裏寫圖片描述
父進程的讀端read3次後關閉讀端,此時子進程依然在write,進程異常終止。
4、寫方前期一直在寫,某一時刻停止,並關閉寫端,讀方一直讀,讀到讀完管道內所有數據管道結束,read返回0值,表示讀到文件結尾
代碼驗證:
這裏寫圖片描述
運行結果:
這裏寫圖片描述

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