九色91_成人精品一区二区三区中文字幕_国产精品久久久久一区二区三区_欧美精品久久_国产精品99久久久久久久vr_www.国产视频

Hello! 歡迎來到小浪云!


【Linux進程通信】二、匿名管道


avatar
小浪云 2025-04-17 23

Ⅰ. 管道一、管道的概念

? 管道是 unix 中最古老的進程間基于文件系統通信的形式。我們把從一個進程連接到另一個進程的一個數據流稱為一個 “管道”。注意管道是單向連通的,不存在說雙向管道,就像生活中水往低處流而不會往高處流一樣!

【Linux進程通信】二、匿名管道

? 進程 A 通過管道將數據寫入到 “公共內存” 中,并且進程 B 可以從該段 “公共內存” 中讀取這些數據,這樣子的話就達到了兩個進程之間的交互!

? 那么有人可能會有問題:既然這段 “公共內存” 是共享的并且都是基于文件系統的,那這個管道文件是不是在磁盤上面呢,然后進程A通過寫入到磁盤中的管道文件,進程B再去讀取這樣子的方式 ???

? 其實不是的,因為我們都知道,文件 IO 的效率是相當的低的,所以操作系統肯定不笨,操作系統會將這個管道文件 load 到內存中,也就是內存級別的文件,而我們兩個進程之間只需要和這個內存級文件打交道即可,這樣子大大的提高了效率!

? 任何一個文件包括兩套資源:

struct file 的操作方法有屬于自己的內核緩沖區,所以父進程和子進程有一份公共的資源:文件系統提供的內核緩沖區,父進程可以向對應的文件的文件緩沖區寫入,子進程可以通過文件緩沖區讀取,此時就完成了進程間通信,這種方式提供的文件稱為管道文件。管道文件本質就是內存級文件,不需要 IO。

? 管道的本質是內核中的緩沖區,通過內核緩沖區實現通信,管道文件只是一個標識符,用于讓多個進程能夠訪問同一塊緩沖區,并非通信介質。

? 并且通過這個內存級別文件的不同形式,我們分為匿名管道和命名管道,后面我們來一一介紹!

二、管道通信原理

? 通過我們上面所說的,管道是個 內存級別的文件(struct file 中特有的,就像內核緩沖區一樣),我們要知道為什么它會叫做 “管道” 呢,是因為它一開始就叫做 “管道” 嗎,那肯定不是,是因為它的原理和 “管道” 是類似的,人們后期才會將其命名為 “管道”,而管道是單通向的,不存在雙向管道!

? 并且我們生活中常見的管道比如說水管、油等等它們的作用就是來傳輸水和油,那么我們計算機中的管道就是傳輸數據,那么這個流向肯定要是一條單向的,我們就不能想象出其原理結構:

【Linux進程通信】二、匿名管道

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

【Linux進程通信】二、匿名管道

?

Ⅱ. 匿名管道一、匿名管道的原理與創建方法

? 在講匿名管道之前呢,我們必須知道管道它的通信方法,而對于匿名管道來說,其實就是 通過 fork 創建子進程!(而命名管道的方法不需要創建子進程,后面會講)

? 為什么對于匿名管道來說需要創建子進程呢 ???

? 匿名管道的名稱由來也是因為這個原因,我們需要通過 fork 創建子進程,我們都知道,子進程會繼承父進程的大部分屬性和內容包括文件描述符(若發生寫時拷貝則會改變),也就是說父進程指向的文件 file,子進程也會指向同一個文件 file(父子進程文件描述符表是獨立的,但是指向的文件是同一個),而就像我們下圖,父子進程可以都指向該管道文件,這樣子的話我們就無需說讓子進程和父進程去專門創建一個帶名稱的管道并且指向它,也就是說我們可以 利用父子進程的繼承性讓子進程繼承這個管道文件達到共同指向它的目的,所以這個管道文件沒必要帶名稱,所以叫做匿名管道!

? 所以,看待管道,就如同看待文件一樣!管道的使用和文件一致,迎合了 “Linux 一切皆文件思想“!

【Linux進程通信】二、匿名管道

? 那么我們如何創建這個匿名管道文件呢 ???

? 下面就得調用我們的系統函數 pipe():

代碼語言:JavaScript代碼運行次數:0運行復制

#include <unistd.h>int pipe(int pipefd[2]);// 功能:創建一無名管道// 參數:pipefd為文件描述符數組,其中fd[0]表示讀端,fd[1]表示寫端// 返回值:成功返回0,失敗返回-1且設置錯誤代碼</unistd.h>

? 大家是不是就會很疑惑這個 pipefd[2] 數組里面放的是固定的值嗎,其實不是的,它會根據當前進程打開文件的個數也就是文件描述符表中 fd_array[] 的有效個數進行返回,但是我們能確定的就是其中 fd[0] 表示的是讀,fd[1] 表示的是寫,而不需要我們關心具體的 fd 是多少!

? 假設我們的進程沒有打開文件,也就是說只打開了默認的三個標準輸入輸出流,那么自然我們的 fd[0] = 3,fd[1] = 4,但如果我們開了一個文件,那么 fd[0] = 4,fd[1] = 5,所以說我們關系的是 fd[0] 和 fd[1] 而不是具體的 3 還是 4 !


? 知道了如何創建匿名管道文件,下面我們來看看如何建立起父子進程之間的通信,也就是讓他們看到同一份資源!下面假設我們讓父進程進行寫入,而子進程進行讀取來模擬過程:

首先我們要創建一個父進程,并讓這個父進程創建并指向這個管道文件接著父進程 fork 創建子進程, 父子進程同時指向管道文件(子進程拷貝父進程大部分內容屬性),并且 fd[0] 和 fd[1] 都是打開的然后父進程關閉讀端也就是 fd[0],子進程關閉寫端也就是 fd[1],這樣子的話就形成了一條單向的管道!

【Linux進程通信】二、匿名管道

? 有人會問能不能不關父進程的讀端等等,答案肯定是不行的,因為不關的話可能在讀寫的時候會發生一些問題,所以 不是我們要的管道通向是必須關的!

? 至于在通信完畢之后,要不要將父子進程中對應的管道關閉呢,這個是建議關閉的,因為不關閉的話,怕會誤操作等等!

二、管道讀寫特征

? 首先我們先打印一個沒有手動打開文件的進程,看看它對應的 fd[0] 和 fd[1] 是多少:

代碼語言:javascript代碼運行次數:0運行復制

#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進程通信】二、匿名管道"></figure><p>? 和我們上面的判斷一樣!</p> <p>? 接下來我們來根據上面講的匿名管道原理,根據通信的步驟,完成父子進程的通信!(下面以子進程寫入,父進程讀取為例)</p>① 讀取快,寫入慢的情況<p>? 這里所謂的讀取快,寫入慢其實就是子進程寫入的時候讓他先 sleep 一會再寫入:</p>代碼語言:javascript<i class="icon-code"></i>代碼運行次數:<!-- -->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>運行<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>復制<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、創建管道文件,打開讀寫端    int fds[2];     int n = pipe(fds);    assert(n == 0);    // 2、創建子進程    pid_t id = fork();    assert(id &gt;= 0);    if(id == 0)    {        // 子進程的通信代碼        close(fds[0]); // 子進程關掉讀端        int cnt = 0;        const char* msg = "i am child, sending msg now!"; // 子進程要發的信息        while(true)        {            char buffer[1024]; // 只有子進程能看到                        // snprintf只是sprintf加上了寫入個數,將格式化內容轉化為字符串            snprintf(buffer, sizeof(buffer), "child msg: %s[%d][%d]", msg, cnt++, getpid());            write(fds[1], buffer, strlen(buffer)); // 不需要算入'

主站蜘蛛池模板:
欧美中文在线
|
中文字幕成人免费视频
|
欧美二区三区
|
中文字幕在线一
|
日韩三级在线
|
男人天堂网址
|
欧美综合一区二区三区
|
亚洲欧美日本国产
|
国产高清在线精品
|
色姑娘av
|
日韩精品一区二区三区中文在线
|
亚洲精品一区二区三区在线
|
91精品国产91久久久久久吃药
|
日韩在线观看网站
|
欧美日韩国产一区二区
|
精品国产一二三区
|
蜜桃在线视频
|
亚洲欧美激情国产综合久久久
|
国产美女一区二区
|
国产精品一区二区福利视频
|
国产一级片网站
|
美女黄网
|
日韩中文字幕一区
|
亚洲国产成人精品女人
|
天堂在线中文
|
国产欧美精品一区二区
|
久久视频免费看
|
亚洲精品一区二区三区蜜桃久
|
日韩av在线一区
|
国产在线区
|
天堂一区二区三区四区
|
久久大陆
|
久久精品久久综合
|
精品久久久精品
|
日本人做爰大片免费观看一老师
|
国产成人一区二区三区
|
一区二区三区在线免费观看
|
精品国产乱码久久久久久丨区2区
|
欧美高清一级片
|
日韩视频一区
|
www.亚洲精品
|