惠網(wǎng) 做網(wǎng)站重慶seo報(bào)價(jià)
Linux進(jìn)程間通信:匿名管道 &命名管道
- 一、進(jìn)程間通信目的
- 二、什么是管道
- 三、匿名管道創(chuàng)建
- 3.1 系統(tǒng)調(diào)用原型
- 3.2 匿名管道創(chuàng)建
- 四、內(nèi)核創(chuàng)建匿名管道過程
- 五、匿名管道性質(zhì)
- 5.1 匿名管道的4種特殊情況
- 5.2 匿名管道的5種特性
- 5.3 測試源代碼
- 六、命名管道
- 6.1 創(chuàng)建命名管道
- 1. 命名行創(chuàng)建
- 6.2 代碼中創(chuàng)建
- 七、命名管道性質(zhì)
- 7.1 匿名管道與命名管道的區(qū)別
- 7.2 命名管道的打開規(guī)則
- 八、進(jìn)程池制作(基于匿名管道和命名管道兩個(gè)版本)
一、進(jìn)程間通信目的
?進(jìn)程間通信的本質(zhì)是不同進(jìn)程看到同一份資源。該資源一般由操作系統(tǒng)提供!!(比如緩沖區(qū))
?進(jìn)程間通信目的主要有:
- 數(shù)據(jù)傳輸:一個(gè)進(jìn)程需要將它的數(shù)據(jù)發(fā)送給另一個(gè)進(jìn)程。
- 資源共享:多個(gè)進(jìn)程之間共享同樣的資源。
- 通知事件:一個(gè)進(jìn)程需要向另一個(gè)或一組進(jìn)程發(fā)送消息,通知它(它們)發(fā)生了某種事件(如進(jìn)程終止時(shí)要通知父進(jìn)程)。
- 進(jìn)程控制:有些進(jìn)程希望完全控制另一個(gè)進(jìn)程的執(zhí)行(如Debug進(jìn)程),此時(shí)控制進(jìn)程希望能夠攔截另一個(gè)進(jìn)程的所有陷入和異常,并能夠及時(shí)知道它的狀態(tài)改變。
二、什么是管道
?管道最早是UNIX中的一種進(jìn)程通信方式。我們把一個(gè)進(jìn)程到另一個(gè)進(jìn)程的一個(gè)數(shù)據(jù)流稱為管道!!管道文件時(shí)一個(gè)純內(nèi)存級(jí)文件,不需要想磁盤刷新。
三、匿名管道創(chuàng)建
3.1 系統(tǒng)調(diào)用原型
?系統(tǒng)中提供了系統(tǒng)調(diào)用接口pipe()
用于創(chuàng)建匿名管道。
#include <unistd.h>int pipe(int pipefd[2]);
pipefd
為輸出型參數(shù),pipefd[1]
為寫端,pipefd[0]
為讀端!!- 創(chuàng)建成功返回0,否則返回-1.
此時(shí)創(chuàng)建結(jié)果如下:
3.2 匿名管道創(chuàng)建
四、內(nèi)核創(chuàng)建匿名管道過程
?在一個(gè)進(jìn)程中,我們分別通過r
和w
兩種方式打開同一個(gè)文件,此時(shí)進(jìn)程文件描述符表中存在兩個(gè)文件描述符fd
,指向兩個(gè)文件結(jié)構(gòu)體對(duì)象file
。但兩個(gè)結(jié)構(gòu)體對(duì)象指向同一個(gè)文件(即相同的inode、同一個(gè)方法集、同一塊緩沖區(qū))!!
?此時(shí)我們通過fork()
創(chuàng)建出子進(jìn)程,子進(jìn)程繼承了父進(jìn)程的file
結(jié)構(gòu)體對(duì)象!(新創(chuàng)建的文件屬于文件管理,不屬于進(jìn)程管理,所以不需要給子進(jìn)程也拷貝一份!)
?此時(shí)我們將父進(jìn)程的寫段關(guān)閉,子進(jìn)程的讀端關(guān)閉(即子寫父讀)。此時(shí)我們就形成了一個(gè)匿名管道(父子兩個(gè)進(jìn)程都看到同一份資源:文件緩沖區(qū);數(shù)據(jù)從子進(jìn)程寫入到文件中,父進(jìn)程從文件中讀取數(shù)據(jù),形成數(shù)據(jù)流)
- 上述這種文件和普通文件不同,不會(huì)向磁盤刷新數(shù)據(jù)。并且文件的緩沖區(qū)是父進(jìn)程和子進(jìn)程所能看到的同一份資源,而向這種文件我們稱之為管道。該管道沒有名字,所以被稱為匿名管道!!
五、匿名管道性質(zhì)
5.1 匿名管道的4種特殊情況
- 正常情況下,如果管道數(shù)據(jù)為空,此時(shí)讀端必讀等待,直到有數(shù)據(jù)為止(寫段向管道中寫入數(shù)據(jù))
- 正常情況下,如果管道數(shù)據(jù)寫滿,此時(shí)寫端會(huì)停止寫入,直到有空間為止!!
- 如果寫端關(guān)閉,讀端一直讀取,讀端讀取到的read返回值為0
- 如果讀端關(guān)閉,寫端一直寫入,此時(shí)操作系統(tǒng)會(huì)通過向?qū)懚税l(fā)送13號(hào)信號(hào),直接殺掉寫端進(jìn)程。
5.2 匿名管道的5種特性
- 匿名管道僅用于具有血緣關(guān)系的進(jìn)程間進(jìn)行相互通信,常用于父子進(jìn)程間。
- 匿名管道默認(rèn)會(huì)給讀寫端提供同步機(jī)制。即管道為空,讀端等待寫端寫入;管道滿了,寫端等待讀端讀取。
- 匿名管道面向字節(jié)流,即通過read讀取指定大小數(shù)據(jù),數(shù)據(jù)過小不會(huì)讀取
- 管道的生命周期隨進(jìn)程。當(dāng)進(jìn)程全部退出時(shí),此時(shí)管道的引用計(jì)數(shù)減為0,操作系統(tǒng)會(huì)將管道文件釋放。
- 匿名管道具有單向通信特點(diǎn),是半雙工通信的一種特殊情況,數(shù)據(jù)只能向一個(gè)方向流動(dòng)。
- 匿名管道具有原子性。當(dāng)要寫入的數(shù)據(jù)量不大于PIPE_BUF時(shí),linux將保證寫入的原子性。即當(dāng)管道中的數(shù)據(jù)量小于PIPE_BUF和指定大小時(shí),此時(shí)讀端會(huì)等待子進(jìn)程寫入。當(dāng)要寫入的數(shù)據(jù)量大于PIPE_BUF時(shí),linux將不再保證寫入的原子性。
5.3 測試源代碼
#include <iostream>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>using namespace std;#define MAX 1024int main()
{//1. 創(chuàng)建管道int pipefd[2];int n = pipe(pipefd);assert(n == 0);(void)n;// 2. 創(chuàng)建子進(jìn)程pid_t id = fork();if(id < 0){perror("fork");return 1;}//3. 關(guān)閉不需要的fd, 形成匿名管道int cnt = 5;if(id == 0)//child{close(pipefd[0]);//子進(jìn)程關(guān)閉讀端while(true){char message[MAX];// snprintf把原本打印到顯示器的信息打印到指定文件中snprintf(message, sizeof(message), "I am child, pid: %d, cnt: %d", getpid(), cnt--);write(pipefd[1], message, strlen(message));//sleep(1);if(cnt == 0) break;cout << "write----" << endl;}cout << "child quit" << endl;exit(0);}//parentclose(pipefd[1]);//父進(jìn)程關(guān)閉寫端while(true){// sleep(1);char buffer[MAX];// read 把pipefd[0]對(duì)于文件中最大517個(gè)字節(jié)寫入buffer緩沖區(qū)中ssize_t n = read(pipefd[0], buffer, 517);if(n == 0){cout << "child quit, me too" << endl;break;}else if(n > 0){buffer[MAX - 1] = 0;cout << "chils say:" << buffer << endl;}break;}cout << "parent quit" << endl;close(pipefd[0]);//回收子進(jìn)程int status;pid_t rid = waitpid(id, &status, 0);if(rid == id){cout << "wait child: " << id << "success" << "exit singal" << (status&0x7f) << endl;}return 0;
}
六、命名管道
?匿名管道中能在具有血緣關(guān)系的進(jìn)程間,進(jìn)行相互通信。那兩個(gè)毫無關(guān)系的獨(dú)立進(jìn)程該如何通信了?
?在不相關(guān)的進(jìn)程之間交換數(shù)據(jù),可以使用FIFO文件來做這項(xiàng)工作的管道稱為命名管道。命名管道是一種特殊類型的文件。
6.1 創(chuàng)建命名管道
1. 命名行創(chuàng)建
?我們可以在命令行上創(chuàng)建命名管道,創(chuàng)建方式如下:
mkfifo xxx
【實(shí)例】:
6.2 代碼中創(chuàng)建
?我們也可以在代碼中使用系統(tǒng)調(diào)用接口創(chuàng)建,函數(shù)原型如下:
#include <sys/types.h>
#include <sys/stat.h>int mkfifo(const char *filename,mode_t mode);// mode為帶創(chuàng)建管道權(quán)限
七、命名管道性質(zhì)
7.1 匿名管道與命名管道的區(qū)別
- 匿名管道由pipe函數(shù)創(chuàng)建并打開;命名管道由mkfifo函數(shù)創(chuàng)建,打開用open。
- FIFO(命名管道)與pipe(匿名管道)之間唯一的區(qū)別在它們創(chuàng)建與打開的方式不同,一但這些工作完
成之后,它們具有相同的語義
7.2 命名管道的打開規(guī)則
如果當(dāng)前打開操作是為讀而打開FIFO時(shí):
- O_NONBLOCK disable:阻塞直到有相應(yīng)進(jìn)程為寫而打開該FIFO。
- O_NONBLOCK enable:立刻返回成功
如果當(dāng)前打開操作是為寫而打開FIFO時(shí):
- O_NONBLOCK disable:阻塞直到有相應(yīng)進(jìn)程為讀而打開該FIFO。
- O_NONBLOCK enable:立刻返回失敗,錯(cuò)誤碼為ENXIO。
八、進(jìn)程池制作(基于匿名管道和命名管道兩個(gè)版本)
Linux:進(jìn)程池制作(基于匿名管道和命名管道兩個(gè)版本)