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