linux c編程:管道

 

 

2在前面介紹過,進程之間交換信息的惟一途徑就是傳送打開的文件。能夠經由fork或者exec來傳送。這一章將介紹新的進程共享方式
每一個進程各自有不一樣的用戶地址空間,任何一個進程的全局變量在另外一個進程中都看不到,因此進程之間要交換數據必須經過內核,在內核中開闢一塊緩衝區,進程A把數據從用戶空間拷到內核緩衝區,進程B再從內核緩衝區把數據讀走,內核提供的這種機制稱爲進程間通訊,以下圖所示 函數

 


 
不一樣進程間的通訊本質:進程之間能夠看到一份公共資源;而提供這份資源的形式或者提供者不一樣,形成了通訊方式不一樣,而 pipe就是提供這份公共資源的形式的一種。
管道是由調用pipe函數來建立
#include <unistd.h>
int pipe (int fd[2]);
fd參數返回兩個文件描述符,fd[0]指向管道的讀端,fd[1]指向管道的寫端。fd[1]的輸出是fd[0]的輸入。
 
管道是如何實現進程間的通訊
(1)父進程建立管道,獲得兩個⽂件描述符指向管道的兩端
 
(2)父進程fork出子進程,⼦進程也有兩個⽂件描述符指向同⼀管道。
 
(3)父進程關閉fd[0],子進程關閉fd[1],即⽗進程關閉管道讀端,⼦進程關閉管讀寫端(由於管道只支持單向通訊)。⽗進程能夠往管道⾥寫,⼦進程能夠從管道⾥讀,管道是⽤環形隊列實現的,數據從寫端流⼊從讀端流出,這樣就實現了進程間通訊。  
 
 
實現以下圖所示 spa

 


 
實現代碼
int chapter15_5()
{
    int n;
    int fd[2];
    pid_t pid;
    char line[MAXLINE];
    if (pipe(fd) < 0)
    {
        printf("pipe error");
    }
    pid=fork();
    if (pid == 0)
    {
        close(fd[1]);
        n=read(fd[0],line,MAXLINE);
        write(STDOUT_FILENO,line,n);
    }
    else
    {
        close(fd[0]);
        write(fd[1],"hello world\n",12);
    }
}
在上面的代碼中,是父進程關閉讀通道,子進程關閉寫通道。父進程向fd[1]中寫入數據,子進程從fd[0]中讀出數據並顯示在終端上。一樣的咱們也能夠子進程關閉讀通道,父進程關閉寫通道,由子進程來寫入數據,父進程讀取數據
 
管道讀取數據的4種狀況:
1 讀端不讀,寫端一直寫blog

寫端不寫,可是讀端一直讀隊列

3 讀端一直讀,且fd[0]保持打開,而寫端寫了一部分數據不寫了,而且關閉fd[1]。 進程

若是一個管道讀端一直在讀數據,而管道寫端的引⽤計數⼤於0決定管道是否會堵塞,引用計數大於0,只讀不寫會致使管道堵塞。ip

4 讀端讀了一部分數據,不讀了且關閉fd[0],寫端一直在寫且f[1]還保持打開狀態。資源

來看下這種異常的代碼:it

int chapter_15_5_1()pip

{變量

    int fd[2];

    int ret = pipe(fd);

    if (ret == -1)

    {

        printf("pipe error\n");

        return 1;

    }

    pid_t id = fork();

    if (id == 0)

    {

        int i = 0;

        close(fd[0]);

        char child[20] = "I am a student";

        while (i<10)

        {

            write(fd[1], child, strlen(child) + 1);

            sleep(2);

            i++;

        }

    }

    else if (id>0)

    {

        close(fd[1]);

        char msg[100];

        int status = 0;

        int j = 0;

        while (j<5)

        {

            memset(msg,'\0',sizeof(msg));

            ssize_t s = read(fd[0], msg, sizeof(msg));

            if (s>0)

            {

                msg[s-1] = '\0';

            }

            printf("%s %d\n",msg,j);

            j++;

        }

        close(fd[0]);

        pid_t ret = waitpid(id, &status, 0);

        printf("exit single(%d),exit(%d)\n",status & 0xff, (status >> 8) & 0xff);

 

    }

    else

    {

        printf("fork error\n");

        return 2;

    }

    return  0;

 

}

在這段代碼中,子進程關閉讀端,每隔2秒向管道寫數據,父進程關閉寫端,當讀了5次數據後就關閉讀端。此時再往管道寫數據則會報錯。

若是一個管道的寫端一直在寫,而讀端的引⽤計數是否⼤於0決定管道是否會堵塞,引用計數大於0,只寫不讀再次調用write會致使管道堵塞;

若是一個管道的讀端一直在讀,而寫端的引⽤計數是否⼤於0決定管道是否會堵塞,引用計數大於0,只讀不寫再次調用read會致使管道堵塞;

而當他們的引用計數等於0時,只寫不讀會致使寫端的進程收到一個SIGPIPE信號,致使進程終止,只寫不讀會致使read返回0,就像讀到⽂件末尾⼀樣。

相關文章
相關標籤/搜索