進程訪問機制,各個進程比較獨立,不能訪問對方的單元,但是進程不可能永遠時對立的,必須涉及到信息的交互。
進程間通信傳遞兩種信息,一種時標記、標誌也就是狀態(同步的狀態信號量,異步的狀態信號),另外一種是數據,即內容(傳送的文件,磁盤、內存(有序的消息隊列、共享內存,socket)、普通上鎖文件、管道(有名管道、無名管道)、mmap。
管道的實現原理:
文件實現進程間的通信,普通文件可以同時被多個進程訪問而無法相互感知,所以,不能使用普通文件來實現進程間通信(flock這個機制實際上是一個同步概念),因此出現了管道這個特殊的文件。由操作系統來維護的一段“內核內存空間”,類似與FIFO這種管道隊列,因此稱爲管道。
(1)上層應用時,它就是文件,可以使用read/write/close等操作。
(2)它是特殊的文件,操作時不能進行lseek.
(3)管道是單向的。如果要實現雙向,只能創建兩個管道。
具體編程
(1)創建無名管道。pipe
int pipe(int pipefd[2]);
pipefd在調用者是一個數組,用來存放管道的兩個返回文件描述符。
pipefd[0]用來讀,pipefd[1]用來寫。
(2)讀寫read/write函數。
read(fd[0],);
write(fd[1]);
(3)無名管道的限制
讀寫的限制
要進程讀,就一定要有人寫,要進行寫,就一定有人要讀。
(1)以阻塞方式讀無名管道,如果當前沒有一個進程(包括自己)與這個管道的寫端關聯,讀操作立即返回。
如果有數據,且大於欲讀出的數據量,讀出試圖讀取的數據大小。
如果有數據,但是小於欲讀出的數據量,讀出所有管道數據。
如果沒有數據,立即返回0.
(2)以阻塞方式讀無名管道,有一個及以上進程(包括自己)與這個管道的寫端關聯,讀操作做如下:
如果有數據,現有數據小於期望讀取的值,讀立即返回現有數據。
如果有數據,現有數據大於期望讀取的值,讀立即返回期望讀寫數據。
如果沒有 數據,則阻塞,當有數據寫入後,喚醒讀操作。
(3)以阻塞方式寫無名管道,如果有一個或者多個進程與這個管道的獨端關聯,如果當前管道已經滿,則阻塞,當有進程讀出數據,喚醒寫操作。
(4)以阻塞方式寫無名管道,如果沒有進程與這個管道的讀端關聯,黨有進程淨產生SIFPIPE的信號,而這個信號的默認操作時種植當前進程,因此很多時候測試無效果,需要安裝信號。
重定向及無名管道應用
<輸入重定向,要求這個輸入文件必須存在。
>輸出重定向,如果文件不存在,創建,否則覆蓋。
>>輸出重定向,如果文件不存在,創建,否則追加。
2>
2>以上時對錯誤輸出信息重定向到文件。
實現ps aux | grep test 或者 who | sort
(1)兩個通信進程,ps aux 用execX函數來執行,grep init 是另一個進程,用execX來執行。爲了方便,由一個父親進程來創建這兩個進程的通信。
(2)管道。這個管道要被兩個進程都訪問,父子進程。
(3)實現重定向。文件描述符複製。在ps aux中輸出重定向,即將fd[1]複製爲1,即以後寫入到1中的數據全部寫入到fd[1]中。默認情況下,一個進程的0,1,22三個文件描述符是默認打開的。因此,怎末來複制實現。
int dup(int oldfd);
複製oldfd爲當前進程中最小未使用的文件描述符。
close(1);
dup(fd[1]);
如果0是默認打開的,dup函數返回1,以後寫入到1的內容也就寫入到fd[1]中。
int dup2(int oldfd,int newfd);
更方便是使用dup2,將oldfd複製爲newfd,如果newfd關聯打開的一個文件,則關閉這個文件。再複製。
dup2(fd[1],1)
能夠保證fd[1]爲後續輸入出重定向的文件。
文件描述符的複製與新開文件是有本質區別的。複製文件描述時,兩個文件描述共享文件表項,即共享讀寫文件。
新打開一個文件,其實時額外的申請文件表項,兩者互不影響。
無名的管道,通信方向要了解創建的管道對應的文件描述符,因此,多用於父子進程或者親緣關係之間,因爲可以方便的實現文件描述符傳遞,
在重定向中還有流的重定向。popen/pclose.