linux進程間通信--管道

作爲進程間通信的第一篇,那麼先來講述一下什麼是進程間通信吧;
因爲每個進程各⾃有不同的⽤戶地址空間,任何⼀個進程的全局變量在另⼀個進程中都看不到所以進 程之間要交換數據必須通過內核,在內核中開闢⼀塊緩衝區,進程1把數據從⽤戶空間拷到內核緩 衝區,進程2再從內核緩衝區把數據讀⾛,內核提供的這種機制稱爲進程間通信(IPC,InterProcess Communication)。

先來說進程間通信第一種方法–匿名管道

其實進程間通信的區別就是在於內核提供的緩衝區的不同,所有才有了不同的通信方法,其本質都是爲了讓不同的進程看到同一片公共的資源就好了;

管道其實可以當作文件來看待,可以理解爲兩個進程在內存中看到了同一個文件;
管道是由int pipe(int filedes[2]) 創建出來的,然後 它有⼀個讀端⼀個寫端,然後通
過filedes參數傳出給⽤戶程序兩個⽂件描述符,filedes[0]指向管道的讀端,filedes[1]指向管道的
寫端(很好記,就像0是標準輸⼊1是標準輸出⼀樣)。所以管道在⽤戶程序看起來就像⼀個打開
的⽂件,通過read(filedes[0]);或者write(filedes[1]);向這個⽂件讀寫數據其實是在讀寫內核緩衝
區。pipe函數調⽤成功返回0,調⽤失敗返回-1。

其過程可以理解:
1.父進程創建管道
⽗進程調⽤pipe開闢管道,得到兩個⽂件描述符指向管道的兩端
父進程創建
2.父進程fork()出子進程
⽗進程調⽤fork創建⼦進程,那麼⼦進程也有兩個⽂件描述符指向同⼀管道

創建子進程
3.父進程關閉fd[0],子進程關閉fd[1]
⽗進程關閉管道讀端,⼦進程關閉管道寫端。⽗進程可以往管道⾥寫,⼦進程可以從管道⾥
讀,管道是⽤環形隊列實現的,數據從寫端流⼊從讀端流出,這樣就實現了進程間通信
關閉對應端口

接下來我們可以實際測試一下:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
    int _pipe[2];
    int ret = pipe(_pipe);//創建管道
    if(ret == -1)//如果pipe失敗
    {
        printf("pipe apply for error!");
        return 1;
    }

    pid_t id = fork();
    if(id < 0)//如果fork失敗
    {
        printf("fork creation fails!");
        return 2;
    }
    else if(id == 0)
    {//child
        close(_pipe[0]);
        char* str = "yang";
        write(_pipe[1],str,strlen(str));
    }
    else
    {//father
        close(_pipe[1]);
        char str[10]={0};
        read(_pipe[0],str,sizeof(str));
        printf("%s\n",str);

        int status = 0;
        pid_t ret1=waitpid(id,&status,0);//等待回收子進程

    }
    return 0;
}

然後運行程序:
運行結果

我們發現子進程成功的打出了父進程傳過去的yang;

但是管道只支持單項通信也就是,比如上面的例子,⽗進程寫⼦進程讀,如果有時候也需要⼦進程寫⽗進程讀,就必須另開⼀個管道。

正是因爲管道是從父進程那裏繼承來的文件描述符表,所有兩個進程要想利用管道通信,就必須要具有血緣關係纔可以;

有了正常的通信之後,就必須來思考一些比較特殊的邊緣效應了;
1. 如果所有指向管道寫端的⽂件描述符都關閉了(管道寫端的引⽤計數等於0),⽽仍然有進程 從管道的讀端讀數據,那麼管道中剩餘的數據都被讀取後,再次read會返回0,就像讀到⽂件末尾⼀樣。
這裏寫圖片描述
這裏寫圖片描述
最後結果
這裏寫圖片描述

2.如果有指向管道寫端的⽂件描述符沒關閉(管道寫端的引⽤計數⼤於0),⽽持有管道寫端的 進程也沒有向管道中寫數據,這時有進程從管道讀端讀數據,那麼管道中剩餘的數據都被讀取後,再次read會阻塞,直到管道中有數據可讀了纔讀取數據並返回。
這裏寫圖片描述
這裏寫圖片描述
最後結果在次阻塞等待

3.如果所有指向管道讀端的⽂件描述符都關閉了(管道讀端的引⽤計數等於0),這時有進程向管道的寫端write,那麼該進程會收到信號SIGPIPE,通常會導致進程異常終⽌。
這裏我用了信號捕獲,這個如果不懂的可直接跳過,只需要知道我把它發的信號捕捉了出來
這裏寫圖片描述
這裏寫圖片描述
13號信號也就是SIGPIPE

4. 如果有指向管道讀端的⽂件描述符沒關閉(管道讀端的引⽤計數⼤於0),⽽持有管道讀端的 進程也沒有從管道中讀數據,這時有進程向管道寫端寫數據,那麼在管道被寫滿時再次write會阻塞,直到管道中有空位置了才寫⼊數據並返回。
這裏寫圖片描述
這裏寫圖片描述
當其寫滿之後便不再寫入
這裏寫圖片描述
直到有進程讀取,纔再次寫入
這裏寫圖片描述

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