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
2 寫端不寫,可是讀端一直讀隊列
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,就像讀到⽂件末尾⼀樣。