進程間通訊——管道

一、進程間通訊緩存

    每一個進程有獨立的用戶地址空間,因此一個進程是看不到另外一個進程中的數據包括全局變量。進程間通訊是須要經過內核來進行的,內核中開闢一塊緩存,不一樣的進程將數據寫到這裏或從這裏讀取,從而實現不一樣進程之間的通訊,內核提供的這種機制稱爲進程間通訊。進程間通訊方式有多種,不一樣的方式提供的共享資源形式不一樣或者提供者不一樣。管道就是這其中的一種。
函數

二、管道的建立測試

    管道的建立使用pipe()系統調用,關於此係統調用可參見另外一篇文章中的描述——高級IO函數spa

三、管道實現進程間通訊.net

    管道通常用於有關係的進程之間的通訊,例如父子進程之間的通訊:
code

  • 父進程建立了一個管道,f[0]、f[1]分別爲管道兩端的文件描述符
  • 父進程經過fork函數建立子進程,此時子進程繼承了父進程的管道,也有一對文件描述符f[0]、f[1]。
  • 因爲管道只能單向傳輸數據,因此父子進程必須一個關閉f[0],另外一個關閉f[1],才能實現通訊。以下圖所示,即爲管道實現進程間通訊的抽象描述。



    管道實現進程間通訊代碼示例:blog

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
	int fd[2];
	int ret = pipe(fd);
	if(ret == -1)
	{
		printf("pipe error\n");
		return 1;
	}

	pid_t id = fork();
	if(id == 0)   //子進程
	{
		close(fd[1]);
		char buf[100];
		while(1)
		{
			memset(buf, '\0', sizeof(buf));
			size_t s = read(fd[0], buf, sizeof(buf));
			if(s > 0)
			{
				buf[s - 1] = '\0';
				printf("%s", buf);
			}
			else
				break;
		}
		close(fd[0]);
		return 0;
	}
	else if(id > 0)  //父進程
	{
		close(fd[0]);
		char* wrbuf = "hello world";
		int i = 5;
		while(i--)
		{
			ret = write(fd[1], wrbuf, strlen(wrbuf));
			if(ret < 0)
			{
				printf("write error\n");
				break;
			}
			sleep(2);
		}
		close(fd[1]);
		int stat_loc;
		wait(&stat_loc);
		return 0;
	}
	else
	{
		printf("fork error\n");
		return 1;
	}
}

四、管道的讀寫狀態繼承

  • 當管道容量滿時,且讀端文件描述符引用計數大於0,則再次調用write會阻塞;
  • 當讀端文件描述符引用計數等於0,寫端再次調用write時,進程會收到SIGPIPE信號,致使進程終止;
  • 當管道數據爲空時,且寫端文件描述符引用計數大於0,則再次調用read會阻塞,直到有數據可讀;
  • 當寫端文件描述符引用計數等於0,讀端再次調用read時,返回0,如同讀到文件末尾(EOF)。

五、管道容量進程

    管道有一個容量限制,規定了若是應用程序沒有將數據從管道中讀走的話,該管道最多能被寫入的數據字節數。當前的Linux,管道容量默認爲65536字節,也可使用fcntl函數修改管道容量。
ip

    測試管道容量,能夠採用對管道只寫不讀,當write阻塞時說明管道已滿,計算write進去的數據字節數,即爲管道容量。

相關文章
相關標籤/搜索