每個進程各自有不同的用戶地址空間,任何一個進程的全局變量在另一個進程中都看不到,所以進程之間要交換數據必須通過內核,在內核中開辟一塊緩沖區,進程1把數據從用戶空間拷到內核緩沖區,進程2再從內核緩沖區把數據讀走,內核提供的這種機制稱為進程間通信(IPC,InterProcess Communication)。
管道是一種最基本的IPC機制,由pipe函數創建:
int pipe(int filedes[2]);
調用pipe函數時在內核中開辟一塊緩沖區(稱為管道)用于通信,它有一個讀端一個寫端,然后通過filedes參數傳出給用戶程序兩個文件描述符,filedes[0]指向管道的讀端,filedes[1]指向管道的寫端(很好記,就像0是標準輸入1是標準輸出一樣)。所以管道在用戶程序看起來就像一個打開的文件,通過read(filedes[0]);或者write(filedes[1]);向這個文件讀寫數據其實是在讀寫內核緩沖區。pipe函數調用成功返回0,調用失敗返回-1。
管道具體的劃分為兩種:命令管道與匿名管道
1.命名管道(FIFO)
匿名管道應用的一個限制就是只能在具有共同祖先(具有親緣關系)的進程間通信。
如果我們想在不相關的進程之間交換數據,可以使用FIFO文件來做這項工作,它經常被稱為命名管道。
命名管道可以從命令行上創建,命令行方法是使用下面這個命令:
$ mkfifo filename
命名管道也可以從程序里創建,相關函數有:
int mkfifo(const char *filename,mode_t mode);
2.匿名管道
匿名管道由pipe函數創建并打開。
命名管道由mkfifo函數創建,打開用open。
FIFO(命名管道)與pipe(匿名管道)之間唯一的區別在它們創建與打開的方式不同,這些工作完成之后,它們具有相同的語義。
3.命名管道的打開規則
如果當前打開操作是為讀而打開FIFO時
O_NONBLOCK disable:阻塞直到有相應進程為寫而打開該FIFO
O_NONBLOCK enable:立刻返回成功
如果當前打開操作是為寫而打開FIFO時
O_NONBLOCK disable:阻塞直到有相應進程為讀而打開該FIFO
O_NONBLOCK enable:立刻返回失敗,錯誤碼為ENXIO
需要注意的是打開的文件描述符默認是阻塞的,大家可以寫兩個很簡單的小程序測試一下,主要也就一條語句
int fd = open("p2", O_WRONLY); 假設p2是命名管道文件,把打開標志換成 O_RDONLY 就是另一個程序了,可以先運行RD程序,此時會阻塞,再在另一個窗口運行WR程序,此時兩個程序都會從open返回成功。非阻塞時也不難測試,open時增加標志位就可以了。