Ⅰ. 管道一、管道的概念
? 管道是 unix 中最古老的進(jìn)程間基于文件系統(tǒng)通信的形式。我們把從一個(gè)進(jìn)程連接到另一個(gè)進(jìn)程的一個(gè)數(shù)據(jù)流稱為一個(gè) “管道”。注意管道是單向連通的,不存在說雙向管道,就像生活中水往低處流而不會往高處流一樣!

? 進(jìn)程 A 通過管道將數(shù)據(jù)寫入到 “公共內(nèi)存” 中,并且進(jìn)程 B 可以從該段 “公共內(nèi)存” 中讀取這些數(shù)據(jù),這樣子的話就達(dá)到了兩個(gè)進(jìn)程之間的交互!
? 那么有人可能會有問題:既然這段 “公共內(nèi)存” 是共享的并且都是基于文件系統(tǒng)的,那這個(gè)管道文件是不是在磁盤上面呢,然后進(jìn)程A通過寫入到磁盤中的管道文件,進(jìn)程B再去讀取這樣子的方式 ???
? 其實(shí)不是的,因?yàn)槲覀兌贾溃募?IO 的效率是相當(dāng)?shù)牡偷模?a >操作系統(tǒng)肯定不笨,操作系統(tǒng)會將這個(gè)管道文件 load 到內(nèi)存中,也就是內(nèi)存級別的文件,而我們兩個(gè)進(jìn)程之間只需要和這個(gè)內(nèi)存級文件打交道即可,這樣子大大的提高了效率!
? 任何一個(gè)文件包括兩套資源:
struct file 的操作方法有屬于自己的內(nèi)核緩沖區(qū),所以父進(jìn)程和子進(jìn)程有一份公共的資源:文件系統(tǒng)提供的內(nèi)核緩沖區(qū),父進(jìn)程可以向?qū)?yīng)的文件的文件緩沖區(qū)寫入,子進(jìn)程可以通過文件緩沖區(qū)讀取,此時(shí)就完成了進(jìn)程間通信,這種方式提供的文件稱為管道文件。管道文件本質(zhì)就是內(nèi)存級文件,不需要 IO。
? 管道的本質(zhì)是內(nèi)核中的緩沖區(qū),通過內(nèi)核緩沖區(qū)實(shí)現(xiàn)通信,管道文件只是一個(gè)標(biāo)識符,用于讓多個(gè)進(jìn)程能夠訪問同一塊緩沖區(qū),并非通信介質(zhì)。
? 并且通過這個(gè)內(nèi)存級別文件的不同形式,我們分為匿名管道和命名管道,后面我們來一一介紹!
二、管道通信原理
? 通過我們上面所說的,管道是個(gè) 內(nèi)存級別的文件(struct file 中特有的,就像內(nèi)核緩沖區(qū)一樣),我們要知道為什么它會叫做 “管道” 呢,是因?yàn)樗婚_始就叫做 “管道” 嗎,那肯定不是,是因?yàn)樗脑砗?“管道” 是類似的,人們后期才會將其命名為 “管道”,而管道是單通向的,不存在雙向管道!
? 并且我們生活中常見的管道比如說水管、油等等它們的作用就是來傳輸水和油,那么我們計(jì)算機(jī)中的管道就是傳輸數(shù)據(jù),那么這個(gè)流向肯定要是一條單向的,我們就不能想象出其原理結(jié)構(gòu):

? 除此之外,我們可以再說說普通文件,我們父進(jìn)程創(chuàng)建子進(jìn)程,子進(jìn)程拷貝父進(jìn)程的文件描述符表,所以都指向 log 文件,而每次我們寫入完畢之后,可能會存在寫滿等情況就會刷新,那么會訪問磁盤,每次讀取時(shí)候又將 log 加載進(jìn)內(nèi)存,不斷的來回,這樣子 IO 次數(shù)非常的多,效率也就非常的低,所以說為什么存在管道文件,其實(shí)就是為了避開普通文件通信的效率底下問題!

?
Ⅱ. 匿名管道一、匿名管道的原理與創(chuàng)建方法
? 在講匿名管道之前呢,我們必須知道管道它的通信方法,而對于匿名管道來說,其實(shí)就是 通過 fork 創(chuàng)建子進(jìn)程!(而命名管道的方法不需要?jiǎng)?chuàng)建子進(jìn)程,后面會講)
? 為什么對于匿名管道來說需要?jiǎng)?chuàng)建子進(jìn)程呢 ???
? 匿名管道的名稱由來也是因?yàn)檫@個(gè)原因,我們需要通過 fork 創(chuàng)建子進(jìn)程,我們都知道,子進(jìn)程會繼承父進(jìn)程的大部分屬性和內(nèi)容包括文件描述符(若發(fā)生寫時(shí)拷貝則會改變),也就是說父進(jìn)程指向的文件 file,子進(jìn)程也會指向同一個(gè)文件 file(父子進(jìn)程文件描述符表是獨(dú)立的,但是指向的文件是同一個(gè)),而就像我們下圖,父子進(jìn)程可以都指向該管道文件,這樣子的話我們就無需說讓子進(jìn)程和父進(jìn)程去專門創(chuàng)建一個(gè)帶名稱的管道并且指向它,也就是說我們可以 利用父子進(jìn)程的繼承性讓子進(jìn)程繼承這個(gè)管道文件達(dá)到共同指向它的目的,所以這個(gè)管道文件沒必要帶名稱,所以叫做匿名管道!
? 所以,看待管道,就如同看待文件一樣!管道的使用和文件一致,迎合了 “Linux 一切皆文件思想“!

? 那么我們?nèi)绾蝿?chuàng)建這個(gè)匿名管道文件呢 ???
? 下面就得調(diào)用我們的系統(tǒng)函數(shù) pipe():
代碼語言:JavaScript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
#include <unistd.h>int pipe(int pipefd[2]);// 功能:創(chuàng)建一無名管道// 參數(shù):pipefd為文件描述符數(shù)組,其中fd[0]表示讀端,fd[1]表示寫端// 返回值:成功返回0,失敗返回-1且設(shè)置錯(cuò)誤代碼</unistd.h>
? 大家是不是就會很疑惑這個(gè) pipefd[2] 數(shù)組里面放的是固定的值嗎,其實(shí)不是的,它會根據(jù)當(dāng)前進(jìn)程打開文件的個(gè)數(shù)也就是文件描述符表中 fd_array[] 的有效個(gè)數(shù)進(jìn)行返回,但是我們能確定的就是其中 fd[0] 表示的是讀,fd[1] 表示的是寫,而不需要我們關(guān)心具體的 fd 是多少!
? 假設(shè)我們的進(jìn)程沒有打開文件,也就是說只打開了默認(rèn)的三個(gè)標(biāo)準(zhǔn)輸入輸出流,那么自然我們的 fd[0] = 3,fd[1] = 4,但如果我們開了一個(gè)文件,那么 fd[0] = 4,fd[1] = 5,所以說我們關(guān)系的是 fd[0] 和 fd[1] 而不是具體的 3 還是 4 !
? 知道了如何創(chuàng)建匿名管道文件,下面我們來看看如何建立起父子進(jìn)程之間的通信,也就是讓他們看到同一份資源!下面假設(shè)我們讓父進(jìn)程進(jìn)行寫入,而子進(jìn)程進(jìn)行讀取來模擬過程:
首先我們要?jiǎng)?chuàng)建一個(gè)父進(jìn)程,并讓這個(gè)父進(jìn)程創(chuàng)建并指向這個(gè)管道文件接著父進(jìn)程 fork 創(chuàng)建子進(jìn)程, 父子進(jìn)程同時(shí)指向管道文件(子進(jìn)程拷貝父進(jìn)程大部分內(nèi)容屬性),并且 fd[0] 和 fd[1] 都是打開的然后父進(jìn)程關(guān)閉讀端也就是 fd[0],子進(jìn)程關(guān)閉寫端也就是 fd[1],這樣子的話就形成了一條單向的管道!

? 有人會問能不能不關(guān)父進(jìn)程的讀端等等,答案肯定是不行的,因?yàn)椴魂P(guān)的話可能在讀寫的時(shí)候會發(fā)生一些問題,所以 不是我們要的管道通向是必須關(guān)的!
? 至于在通信完畢之后,要不要將父子進(jìn)程中對應(yīng)的管道關(guān)閉呢,這個(gè)是建議關(guān)閉的,因?yàn)椴魂P(guān)閉的話,怕會誤操作等等!
二、管道讀寫特征
? 首先我們先打印一個(gè)沒有手動打開文件的進(jìn)程,看看它對應(yīng)的 fd[0] 和 fd[1] 是多少:
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
#include <iostream>#include <unistd.h>#include <cassert>using namespace std;int main(){ int fds[2]; int n = pipe(fds); assert(n != -1); // fds[0]:讀 // fds[1]:寫 cout <figure class=""><img src="https://img.php.cn/upload/article/001/503/042/174486663471139.jpg" alt="【Linux進(jìn)程通信】二、匿名管道"></figure><p>? 和我們上面的判斷一樣!</p> <p>? 接下來我們來根據(jù)上面講的匿名管道原理,根據(jù)通信的步驟,完成父子進(jìn)程的通信!(下面以子進(jìn)程寫入,父進(jìn)程讀取為例)</p>① 讀取快,寫入慢的情況<p>? 這里所謂的讀取快,寫入慢其實(shí)就是子進(jìn)程寫入的時(shí)候讓他先 sleep 一會再寫入:</p>代碼語言:javascript<i class="icon-code"></i>代碼運(yùn)行次數(shù):<!-- -->0<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewbox="0 0 16 16" fill="none"><path d="M6.66666 10.9999L10.6667 7.99992L6.66666 4.99992V10.9999ZM7.99999 1.33325C4.31999 1.33325 1.33333 4.31992 1.33333 7.99992C1.33333 11.6799 4.31999 14.6666 7.99999 14.6666C11.68 14.6666 14.6667 11.6799 14.6667 7.99992C14.6667 4.31992 11.68 1.33325 7.99999 1.33325ZM7.99999 13.3333C5.05999 13.3333 2.66666 10.9399 2.66666 7.99992C2.66666 5.05992 5.05999 2.66659 7.99999 2.66659C10.94 2.66659 13.3333 5.05992 13.3333 7.99992C13.3333 10.9399 10.94 13.3333 7.99999 13.3333Z" fill="currentcolor"></path></svg>運(yùn)行<svg width="16" height="16" viewbox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.5 15.5V3.5H14.5V15.5H4.5ZM12.5 5.5H6.5V13.5H12.5V5.5ZM9.5 2.5H3.5V12.5H1.5V0.5H11.5V2.5H9.5Z" fill="currentcolor"></path></svg>復(fù)制<pre class="prism-token token line-numbers javascript">#include <iostream>#include <unistd.h>#include <cassert>#include <sys>#include <sys>#include <cstdio>#include <cstring>#include <cstdlib>using namespace std;int main(){ // 1、創(chuàng)建管道文件,打開讀寫端 int fds[2]; int n = pipe(fds); assert(n == 0); // 2、創(chuàng)建子進(jìn)程 pid_t id = fork(); assert(id >= 0); if(id == 0) { // 子進(jìn)程的通信代碼 close(fds[0]); // 子進(jìn)程關(guān)掉讀端 int cnt = 0; const char* msg = "i am child, sending msg now!"; // 子進(jìn)程要發(fā)的信息 while(true) { char buffer[1024]; // 只有子進(jìn)程能看到 // snprintf只是sprintf加上了寫入個(gè)數(shù),將格式化內(nèi)容轉(zhuǎn)化為字符串 snprintf(buffer, sizeof(buffer), "child msg: %s[%d][%d]", msg, cnt++, getpid()); write(fds[1], buffer, strlen(buffer)); // 不需要算入' 主站蜘蛛池模板: 中文字幕加勒比 | 成人av网站在线观看 | 91精品国产91久久久久久最新 | 国产精品一区二区三区四区 | 亚洲国产精品久久久久婷婷老年 | 欧美中文在线 | 欧美日韩在线视频一区 | 中文字幕亚洲欧美日韩在线不卡 | 中文字幕在线中文 | 精品欧美一区二区三区久久久 | 国产成人精品久久二区二区91 | 欧美中文字幕一区二区三区亚洲 | 久久www免费视频 | 国产精品视频一区二区三区不卡 | 毛片高清 | 高清久久久 | 一区二区三区在线播放视频 | 久久精品一区二区 | 亚洲精品乱码久久久久久9色 | 国产精品特级毛片一区二区三区 | 麻豆亚洲 | 日日久 | 99久久亚洲 | 国产偷自视频区视频 | 中文字幕在线观看www | 男人的天堂一级片 | 亚洲一区二区不卡在线观看 | 欧美做暖暖视频 | 亚洲另类自拍 | 亚洲综合久久久 | 午夜视频一区 | 成人小视频在线观看 | 国产原创在线观看 | 日韩精品区| 97色综合| 一本色道精品久久一区二区三区 | 亚洲性视频网站 | 午夜无码国产理论在线 | 一区中文字幕 | 中文字幕视频一区 | 玖玖玖在线 |