对OS实验中的“管道”的一点儿理解
管道通信機(jī)制
管道 pipe 是進(jìn)程間通信最基本的一種機(jī)制。在內(nèi)存中建立的管道稱為無名管道,
在磁盤上建立的管道稱為有名管道。無名管道隨著進(jìn)程的撤消而消失,有名管道則可
以長久保存,shell 命令符| 建立的就是無名管道,而 shell 命令 mkfifo 建立的是有名
管道。兩個進(jìn)程可以通過管道一個在管道一端向管道發(fā)送其輸出,給另一進(jìn)程可以在
管道的另一端從管道得到其輸入.管道以半雙工方式工作,即它的數(shù)據(jù)流是單方向的.
因此使用一個管道一般的規(guī)則是讀管道數(shù)據(jù)的進(jìn)程關(guān)閉管道寫入端,而寫管道進(jìn)程關(guān)
閉其讀出端。管道既可以采用同步方式工作也可以采用異步方式工作。
對“讀管道數(shù)據(jù)的進(jìn)程關(guān)閉管道寫入端,而寫管道進(jìn)程關(guān)閉其讀出端”的理解:
用反證法的思想,假如寫管道的進(jìn)程關(guān)閉管道寫入端,那么,讀管道進(jìn)程已經(jīng)不想讀管道了,寫管道進(jìn)程還在源源不斷地寫入數(shù)據(jù),那么管道是不是就會太慢而導(dǎo)致“炸裂”?,所以是讀管道進(jìn)程關(guān)閉管道的寫入端。而寫管道的進(jìn)程關(guān)閉讀出端,也很好理解,寫管道的進(jìn)程不想寫了,它就關(guān)閉讀出端,讀管道進(jìn)程讀完管道中剩余的數(shù)據(jù)后自然也讀不到數(shù)據(jù)了。
上面這句話的意思是,讀管道數(shù)據(jù)的進(jìn)程在讀數(shù)據(jù)之前要關(guān)閉管道寫入端,寫管道進(jìn)程在寫數(shù)據(jù)之前關(guān)閉其讀出端,在讀管道數(shù)據(jù)的進(jìn)程讀完數(shù)據(jù)之后,關(guān)閉管道的讀出端(0端),寫管道進(jìn)程在寫完數(shù)據(jù)之后關(guān)閉其寫入端(1端)。
匿名管道的局限性主要有兩點:一是由于管道建立在內(nèi)存中,所以它的容量不可能很大;二是管道所傳送的是無格式字節(jié)流,這就要求使用管道的雙方實現(xiàn)必須對傳輸?shù)臄?shù)據(jù)格式進(jìn)行約定。
例子:在父子進(jìn)程之間利用匿名管道通信。
#include <unist.h>
#include <string.h>
#include <wait.h>
#include <stdio.h>
#define MAX_LINE 80
int main()
{
int testPipe[2], ret;
char buf[MAX_LINE + 1];
const char * testbuf = “主程序發(fā)送的數(shù)據(jù)”;
}
————————————————
版權(quán)聲明:本文為CSDN博主「Yngz_Miao」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_38410730/article/details/81569852
pipe 系統(tǒng)調(diào)用的語法為:
#include <unistd.h>
int pipe(int pipe_id[2]);
pipe 建立一個無名管道,pipe_id[0]中和 pipe_id[1]將放入管道兩端的描述符,如果
pipe 執(zhí)行成功返回 0。.出錯返回-1.
管道讀寫的系統(tǒng)調(diào)用語法為:
#include <unistd.h>
ssize_t read(int pipe_id,const void *buf,size_t count);
ssize_t write(int pipe_id,const void *buf,size_t count);
read 和 write 分別在管道的兩端進(jìn)行讀和寫。
pipe_id 是 pipe 系統(tǒng)調(diào)用返回的管道描述符。
Buf 是數(shù)據(jù)緩沖區(qū)首地址,
count 說明數(shù)據(jù)緩沖區(qū)以 size_t 為單位的長度。
read 和 write 的返回值為它們實際讀寫的數(shù)據(jù)單位。
注意1.管道的讀寫默認(rèn)的通信方式為同步讀寫方式,即如果管道讀端無數(shù)據(jù)則讀者阻塞直到數(shù)據(jù)到達(dá),反之如果管道寫端有數(shù)據(jù)則寫者阻塞直到數(shù)據(jù)被讀走。
注意2.上面說“Buf 是數(shù)據(jù)緩沖區(qū)首地址”,這里的數(shù)據(jù)緩沖區(qū)不要誤以為是管道對應(yīng)一片數(shù)據(jù)緩沖區(qū),而是,往管道里寫入數(shù)據(jù)時,可以把已有的一個數(shù)據(jù)緩沖區(qū)作為寫入數(shù)據(jù)的數(shù)據(jù)來源,例如:這時的數(shù)據(jù)緩沖區(qū)可以是已經(jīng)定義好內(nèi)容的一個字符數(shù)組,那么這是一個“輸入數(shù)據(jù)緩沖區(qū)”或者“寫入數(shù)據(jù)緩沖區(qū)”,而從管道中讀出數(shù)據(jù)時,把讀出來的數(shù)據(jù)放在哪里呢?可以事先定義一個字符數(shù)組,然后把此數(shù)組名作為參數(shù)傳入read()函數(shù)中,以便把讀出的數(shù)據(jù)存放在這個數(shù)組中,那么,這個數(shù)組就相當(dāng)于一個"輸出數(shù)據(jù)緩沖區(qū)”/“讀出數(shù)據(jù)緩沖區(qū)”,第三個參數(shù)可以傳入數(shù)據(jù)緩沖區(qū)的大小(可以是你此前定義好的數(shù)組的大小)
疑問:
1.有管道的容量這個概念嗎?每次最多可以寫入或者讀出多少個數(shù)據(jù)呢?
答:好像沒有限制,讀多少都可以?是面向字節(jié)流的。
命令 ulimit -a可以查看管道的大小,這是內(nèi)核設(shè)定的為8*512byte=4k bit
管道的創(chuàng)建
管道是一種最基本的進(jìn)程間通信機(jī)制。管道由pipe函數(shù)來創(chuàng)建:
SYNOPSIS
#include <unistd.h>
int pipe(int pipefd[2]);
調(diào)用pipe函數(shù),會在內(nèi)核中開辟出一塊緩沖區(qū)用來進(jìn)行進(jìn)程間通信,這塊緩沖區(qū)稱為管道,它有一個讀端和一個寫端。
pipe函數(shù)接受一個參數(shù),是包含兩個整數(shù)的數(shù)組,如果調(diào)用成功,會通過pipefd[2]傳出給用戶程序兩個文件描述符,需要注意pipefd [0]指向管道的讀端, pipefd [1]指向管道的寫端,那么此時這個管道對于用戶程序就是一個文件,可以通過read(pipefd [0]);或者write(pipefd [1])進(jìn)行操作。pipe函數(shù)調(diào)用成功返回0,否則返回-1。
pipe的特點:
只能單向通信
只能血緣關(guān)系的進(jìn)程進(jìn)行通信
依賴于文件系統(tǒng)
4、生命周期隨進(jìn)程
面向字節(jié)流的服務(wù)
管道內(nèi)部提供了同步機(jī)制
說明:因為管道通信是單向的,在上面的例子中我們是通過子進(jìn)程寫父進(jìn)程來讀,如果想要同時父進(jìn)程寫而子進(jìn)程來讀,就需要再打開另外的管道;
管道的讀寫端通過打開的文件描述符來傳遞,因此要通信的兩個進(jìn)程必須從它們的公共祖先那里繼承管道的件描述符。 上面的例子是父進(jìn)程把文件描述符傳給子進(jìn)程之后父子進(jìn)程之 間通信,也可以父進(jìn)程fork兩次,把文件描述符傳給兩個子進(jìn)程,然后兩個子進(jìn)程之間通信, 總之 需要通過fork傳遞文件描述符使兩個進(jìn)程都能訪問同一管道,它們才能通信。(自己在實驗過程中發(fā)現(xiàn),程序中不一定要有fork()才能使用管道,同一個進(jìn)程的多個線程也可以使用管道通信)
四個特殊情況:
如果所有指向管道寫端的文件描述符都關(guān)閉了,而仍然有進(jìn)程從管道的讀端讀數(shù)據(jù),那么管道中剩余的數(shù)據(jù)都被讀取后,再次read會返回0,就像讀到文件末尾一樣
如果有指向管道寫端的文件描述符沒關(guān)閉,而持有管道寫端的進(jìn)程也沒有向管道中寫數(shù)據(jù),這時有進(jìn)程從管道讀端讀數(shù)據(jù),那么管道中剩余的數(shù)據(jù)都被讀取后,再次read會阻塞,直到管道中有數(shù)據(jù)可讀了才讀取數(shù)據(jù)并返回。
如果所有指向管道讀端的文件描述符都關(guān)閉了,這時有進(jìn)程指向管道的寫端write,那么該進(jìn)程會收到信號SIGPIPE,通常會導(dǎo)致進(jìn)程異常終止。
如果有指向管道讀端的文件描述符沒關(guān)閉,而持有管道寫端的進(jìn)程也沒有從管道中讀數(shù)據(jù),這時有進(jìn)程向管道寫端寫數(shù)據(jù),那么在管道被寫滿時再write會阻塞,直到管道中有空位置了才寫入數(shù)據(jù)并返回。
此段的參考來源:https://blog.csdn.net/qq_36829091/article/details/80138836
·································································································
LINUX 管道實現(xiàn)的機(jī)制
從本質(zhì)上說,管道也是一種文件,但他又和一般的文件有所不同,管道可以克服使用文件進(jìn)行通信的兩個問題
- 限制管道的大小。實際上,管道是一個固定大小的緩沖區(qū)。在Linux中該換沖區(qū)的大小為一頁,4k
使得他的大小不像文件那樣不加檢驗的增長。使用固定緩沖區(qū)也會帶來問題,比如再寫管道時可能變滿
當(dāng)這種情況發(fā)生時,隨后對管道的write()調(diào)用被阻塞,等待某些數(shù)據(jù)被讀取,以便騰出足夠的空間供
write()調(diào)用。
- 讀取工作也可能比寫的進(jìn)程快。當(dāng)所有進(jìn)程的數(shù)據(jù)被讀取完時,一個隨后的read()調(diào)用將默認(rèn)的被阻塞、
管道變空。這種情況發(fā)生時,一個隨后的read()調(diào)用將被默認(rèn)的阻塞,等待某些數(shù)據(jù)被寫入,這樣就解決了read()
調(diào)用將被默認(rèn)的阻塞,等待某些數(shù)據(jù)將被寫入,這解決了read()調(diào)用返回文件結(jié)束的問題。
————————————————
版權(quán)聲明:上面一段為CSDN博主「魏爾肖」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_35116353/article/details/60963287
總結(jié)
以上是生活随笔為你收集整理的对OS实验中的“管道”的一点儿理解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 多线程pthread_join()的作用
- 下一篇: C/C++中的指针变量可以相互赋值,使得