引言
當(dāng)今計(jì)算機(jī)系統(tǒng)中,進(jìn)程間通信扮演著至關(guān)重要的角色。隨著計(jì)算機(jī)系統(tǒng)的發(fā)展和復(fù)雜性的增加,多個(gè)進(jìn)程之間的協(xié)作變得更加必要和常見(jiàn)。進(jìn)程間通信使得不同進(jìn)程能夠共享資源、協(xié)調(diào)工作、傳輸數(shù)據(jù),并實(shí)現(xiàn)更加復(fù)雜和強(qiáng)大的功能。本文將深入探討進(jìn)程間的通信,以及管道的作用。它為多個(gè)進(jìn)程提供了一種有效的交互方式,使得系統(tǒng)能夠更好地協(xié)同工作、共享資源,并實(shí)現(xiàn)更高級(jí)別的功能。通過(guò)恰當(dāng)?shù)剡x擇和使用進(jìn)程間通信的方式,我們可以構(gòu)建出高效、可靠且高度協(xié)同的系統(tǒng)。下面話不多說(shuō)坐穩(wěn)扶好咱們要開(kāi)車(chē)了??
一、進(jìn)程間通信概念
進(jìn)程間通信(IPC)是操作系統(tǒng)中的一個(gè)重要概念,它允許不同的進(jìn)程在執(zhí)行過(guò)程中交換數(shù)據(jù)、共享資源、協(xié)調(diào)行為等。在多道程序設(shè)計(jì)環(huán)境下,多個(gè)進(jìn)程可能需要相互通信以完成復(fù)雜的任務(wù),而進(jìn)程間通信提供了各種機(jī)制來(lái)實(shí)現(xiàn)這種交互。
二、進(jìn)程間通信目的
??進(jìn)程間通信的主要目的包括:
- 數(shù)據(jù)交換:允許進(jìn)程之間傳遞數(shù)據(jù),比如傳輸文件、文本、圖像等信息。
- 資源共享:多個(gè)進(jìn)程可以訪問(wèn)和共享同一塊內(nèi)存區(qū)域,以便協(xié)同完成某項(xiàng)任務(wù)。
- 進(jìn)程控制:允許一個(gè)進(jìn)程控制另一個(gè)進(jìn)程的行為,比如啟動(dòng)、暫停、終止等。
- 同步與互斥:確保多個(gè)進(jìn)程能夠按照特定的順序執(zhí)行,避免競(jìng)態(tài)條件和數(shù)據(jù)沖突。
- 通知事件:一個(gè)進(jìn)程需要向另一個(gè)或一組進(jìn)程發(fā)送消息,通知它(它們)發(fā)生了某種事件(如進(jìn)程終止時(shí)要通知父進(jìn)程)。
三、進(jìn)程間通信分類
??以下是幾種常見(jiàn)的進(jìn)程間通信方式:
-
管道(Pipe):管道是一種半雙工的通信方式,用于具有親緣關(guān)系的進(jìn)程間通信。它可以是匿名管道(使用
pipe
系統(tǒng)調(diào)用)或命名管道(使用mkfifo
命令),并且數(shù)據(jù)只能在一個(gè)方向上流動(dòng)。 -
信號(hào)(Signal):信號(hào)是一種異步的通信機(jī)制,用于通知進(jìn)程發(fā)生了某種事件。進(jìn)程可以向另一個(gè)進(jìn)程發(fā)送信號(hào),比如終止信號(hào)(
SIGTERM
)、中斷信號(hào)(SIGINT
)等。 -
消息隊(duì)列(Message Queue):消息隊(duì)列是一種消息傳遞機(jī)制,可以在不同進(jìn)程之間按隊(duì)列方式傳遞數(shù)據(jù)。它允許一個(gè)進(jìn)程向另一個(gè)進(jìn)程發(fā)送消息,而不需要直接的數(shù)據(jù)連接。
-
共享內(nèi)存(Shared Memory):共享內(nèi)存允許多個(gè)進(jìn)程訪問(wèn)同一塊物理內(nèi)存,因此它是最快的 IPC 方式之一。但需要開(kāi)發(fā)者自行解決競(jìng)爭(zhēng)條件和同步的問(wèn)題。
-
信號(hào)量(Semaphores):信號(hào)量是一種計(jì)數(shù)器,用于控制對(duì)共享資源的訪問(wèn)。它通常與共享內(nèi)存一起使用,以避免多個(gè)進(jìn)程同時(shí)訪問(wèn)共享內(nèi)存時(shí)產(chǎn)生的競(jìng)爭(zhēng)條件。
-
套接字(Socket):套接字是一種進(jìn)程間通信的常見(jiàn)方式,可以用于不同主機(jī)之間的通信,也可以用于同一主機(jī)上不同進(jìn)程之間的通信。
四、管道
1. 什么是管道
管道(Pipe)是一種在UNIX和類UNIX系統(tǒng)中用于進(jìn)程間通信的機(jī)制。管道允許一個(gè)進(jìn)程將其輸出直接發(fā)送到另一個(gè)進(jìn)程的輸入,從而實(shí)現(xiàn)兩個(gè)進(jìn)程之間的數(shù)據(jù)傳輸。
??管道的特點(diǎn)包括:
- 管道是一種半雙工的通信方式,數(shù)據(jù)只能在一個(gè)方向上流動(dòng)。
- 管道通常用于實(shí)現(xiàn)父子進(jìn)程之間的通信,例如一個(gè)進(jìn)程的輸出連接到另一個(gè)進(jìn)程的輸入,實(shí)現(xiàn)數(shù)據(jù)傳遞和處理。
- 管道的數(shù)據(jù)是以先進(jìn)先出(FIFO)的方式傳輸?shù)?,保持了?shù)據(jù)的順序性。
2. 匿名管道
(1)創(chuàng)建和關(guān)閉
?pipe() 函數(shù)
在Linux系統(tǒng)中,pipe()
函數(shù)用于創(chuàng)建匿名管道,它是一個(gè)系統(tǒng)調(diào)用函數(shù),位于<unistd.h>
頭文件中。該函數(shù)創(chuàng)建一個(gè)管道,返回兩個(gè)文件描述符,一個(gè)用于讀取數(shù)據(jù),另一個(gè)用于寫(xiě)入數(shù)據(jù)。
語(yǔ)法
#include <unistd.h>
int pipe(int pipefd[2]);
參數(shù)
-
pipefd
: 一個(gè)整型數(shù)組,用于存儲(chǔ)管道的文件描述符。pipefd[0]
用于從管道中讀取數(shù)據(jù),pipefd[1]
用于向管道中寫(xiě)入數(shù)據(jù)。
返回值
- 若成功,返回值為0;若失敗,返回值為-1,并設(shè)置errno來(lái)指示錯(cuò)誤類型。
?創(chuàng)建匿名管道
- 使用
pipe()
系統(tǒng)調(diào)用來(lái)創(chuàng)建匿名管道。pipe()
系統(tǒng)調(diào)用會(huì)創(chuàng)建一個(gè)管道,返回兩個(gè)文件描述符,一個(gè)用于讀取數(shù)據(jù),另一個(gè)用于寫(xiě)入數(shù)據(jù)。 - 在Linux系統(tǒng)中,可以通過(guò)命令行工具或者編程語(yǔ)言來(lái)使用
pipe()
系統(tǒng)調(diào)用創(chuàng)建匿名管道。 - 以下是使用C語(yǔ)言創(chuàng)建匿名管道的示例代碼:
#include <unistd.h>
int main() {
int pipefd[2];
if (pipe(pipefd) == -1) {
// 處理創(chuàng)建失敗的情況
}
// 現(xiàn)在pipefd[0]是用于讀取的文件描述符,pipefd[1]是用于寫(xiě)入的文件描述符
}
?關(guān)閉匿名管道
- 匿名管道的關(guān)閉通常由操作系統(tǒng)自動(dòng)處理,當(dāng)所有指向管道的文件描述符都關(guān)閉時(shí),操作系統(tǒng)會(huì)自動(dòng)關(guān)閉管道。
- 在編程中,可以通過(guò)
close()
系統(tǒng)調(diào)用顯式地關(guān)閉管道的讀取端或?qū)懭攵恕?/li> - 以下是使用C語(yǔ)言關(guān)閉匿名管道的示例代碼:
#include <unistd.h>
int main() {
int pipefd[2];
if (pipe(pipefd) == -1) {
// 處理創(chuàng)建失敗的情況
}
// 在適當(dāng)?shù)臅r(shí)機(jī)關(guān)閉管道
close(pipefd[0]); // 關(guān)閉讀取端
close(pipefd[1]); // 關(guān)閉寫(xiě)入端
}
(2)通信方式
?父子進(jìn)程之間的通信:父子進(jìn)程可以通過(guò)匿名管道進(jìn)行通信。通常的做法是在調(diào)用fork()之后,子進(jìn)程繼承了父進(jìn)程的文件描述符,包括管道。子進(jìn)程可以關(guān)閉不需要的文件描述符,然后使用write()函數(shù)向管道中寫(xiě)入數(shù)據(jù),父進(jìn)程則使用read()函數(shù)從管道中讀取數(shù)據(jù)。
?兄弟進(jìn)程之間的通信:兄弟進(jìn)程之間也可以通過(guò)匿名管道進(jìn)行通信。通常的做法是在調(diào)用pipe()和fork()之后,子進(jìn)程再次調(diào)用fork()創(chuàng)建兄弟進(jìn)程。然后兄弟進(jìn)程可以通過(guò)管道進(jìn)行通信,一個(gè)進(jìn)程負(fù)責(zé)寫(xiě)入,另一個(gè)進(jìn)程負(fù)責(zé)讀取。
(3)用法示例
- 在Shell腳本中,可以使用管道將一個(gè)命令的輸出傳遞給另一個(gè)命令進(jìn)行處理,比如
command1 | command2
。 - 在C語(yǔ)言或其他編程語(yǔ)言中,可以通過(guò)創(chuàng)建管道來(lái)實(shí)現(xiàn)父子進(jìn)程之間的通信,或者在多個(gè)兄弟進(jìn)程之間進(jìn)行數(shù)據(jù)交換(后面進(jìn)程池會(huì)細(xì)講示例)。
(4)匿名管道的特點(diǎn)
-
阻塞式讀寫(xiě):
- 當(dāng)管道讀取端為空時(shí),嘗試從管道中讀取數(shù)據(jù)的進(jìn)程將會(huì)被阻塞,直到有數(shù)據(jù)可供讀取為止。讀取端的進(jìn)程會(huì)等待直到管道中有數(shù)據(jù)可用,或者直到收到信號(hào)中斷。
- 當(dāng)管道寫(xiě)入端已滿時(shí),嘗試向管道中寫(xiě)入數(shù)據(jù)的進(jìn)程將會(huì)被阻塞,直到有足夠的空間可以寫(xiě)入為止。這個(gè)時(shí)候,寫(xiě)入端的進(jìn)程會(huì)等待直到管道中有足夠的空間,或者直到收到信號(hào)中斷。
-
數(shù)據(jù)順序性:
- 匿名管道保證數(shù)據(jù)的順序性,數(shù)據(jù)是以先進(jìn)先出(FIFO)的方式傳輸?shù)?,從而保持了?shù)據(jù)的順序性。
-
局限性:
- 匿名管道通常適用于具有親緣關(guān)系的進(jìn)程間通信,無(wú)法用于無(wú)親緣關(guān)系的進(jìn)程間通信。
- 匿名管道只能在本地進(jìn)程間通信,無(wú)法用于遠(yuǎn)程通信。
-
單向通信:匿名管道是一種單向通信機(jī)制,數(shù)據(jù)只能在一個(gè)方向上傳輸。其中一個(gè)進(jìn)程負(fù)責(zé)寫(xiě)入數(shù)據(jù),而另一個(gè)進(jìn)程負(fù)責(zé)讀取數(shù)據(jù)。這使得匿名管道適用于一些特定的通信場(chǎng)景,如父子進(jìn)程或者兄弟進(jìn)程之間的通信。
-
半雙工通信:匿名管道是半雙工的,意味著它可以在兩個(gè)進(jìn)程之間進(jìn)行雙向通信,但是不能同時(shí)進(jìn)行讀和寫(xiě)操作。雖然它可以實(shí)現(xiàn)雙向通信,但是在任意給定的時(shí)間點(diǎn),數(shù)據(jù)只能在一個(gè)方向上傳輸。
-
自動(dòng)關(guān)閉:當(dāng)所有指向管道的文件描述符全部關(guān)閉時(shí),操作系統(tǒng)會(huì)自動(dòng)關(guān)閉管道。這樣做可以確保在程序結(jié)束時(shí)釋放資源,并且不會(huì)造成資源泄漏。
3. 運(yùn)用匿名管道建立進(jìn)程池
#include <iostream>
#include <vector>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctime>
#include <cstdlib>
#include <cassert>
#define PROCESS_NUM 5 // 定義常量 PROCESS_NUM 為 5
using namespace std;
// 從文件描述符 waitFd 中讀取命令
int waitCommand(int waitFd, bool &quit) {
uint32_t command = 0;
ssize_t s = read(waitFd, &command, sizeof(command)); // 從文件描述符中讀取命令
if (s == 0) { // 如果成功讀取到命令
quit = true; // 標(biāo)記為需要退出
return -1;
}
assert(s == sizeof(uint32_t)); // 斷言讀取的字節(jié)數(shù)與命令長(zhǎng)度相等
return command; // 返回讀取到的命令
}
// 向指定的進(jìn)程發(fā)送命令,并在標(biāo)準(zhǔn)輸出中打印相關(guān)信息
void sendAndWakeup(pid_t who, int fd, uint32_t command) {
write(fd, &command, sizeof(command)); // 向文件描述符中寫(xiě)入命令
cout << "main process: call process " << who << " execute " << desc[command] << " through " << fd << endl; // 打印相關(guān)信息
}
int main()
{
load(); // 加載一些內(nèi)容
vector<pair<pid_t, int>> slots; // 用于保存子進(jìn)程的PID和管道寫(xiě)端文件描述符
// 先創(chuàng)建多個(gè)進(jìn)程
for (int i = 0; i < PROCESS_NUM; i++)
{
int pipefd[2] = {0};
assert(pipe(pipefd) == 0); // 創(chuàng)建管道并檢查是否成功
pid_t id = fork();
assert(id != -1); // 檢查fork()是否成功
if (id == 0) // 子進(jìn)程邏輯
{
close(pipefd[1]); // 關(guān)閉寫(xiě)端
while (true)
{
bool quit = false;
int command = waitCommand(pipefd[0], quit); // 等待命令
if (quit)
break; // 如果收到退出命令,則退出循環(huán)
if (command >= 0 && command < handlerSize())
{
dummyHandler(); // 執(zhí)行對(duì)應(yīng)的命令處理函數(shù)
}
else
{
cout << "非法command: " << command << endl;
}
}
exit(1);
}
else // 父進(jìn)程邏輯
{
close(pipefd[0]); // 關(guān)閉子進(jìn)程的讀端
slots.push_back(pair<pid_t, int>(id, pipefd[1])); // 保存子進(jìn)程的PID和寫(xiě)端管道文件描述符
}
}
// 父進(jìn)程派發(fā)任務(wù)
srand((unsigned long)time(nullptr) ^ getpid() ^ 23323123123L); // 設(shè)置隨機(jī)數(shù)種子
while (true)
{
int command = rand() % handlerSize(); // 隨機(jī)選擇一個(gè)任務(wù)
int choice = rand() % slots.size(); // 隨機(jī)選擇一個(gè)子進(jìn)程
sendAndWakeup(slots[choice].first, slots[choice].second, command); // 向選定的子進(jìn)程發(fā)送任務(wù)
sleep(1); // 休眠一秒
}
// 關(guān)閉fd, 所有的子進(jìn)程都會(huì)退出
for (const auto &slot : slots)
{
close(slot.second); // 關(guān)閉所有子進(jìn)程的寫(xiě)端
}
// 回收所有的子進(jìn)程信息
for (const auto &slot : slots)
{
waitpid(slot.first, nullptr, 0); // 回收子進(jìn)程
}
}
這段代碼是一個(gè)簡(jiǎn)單的進(jìn)程調(diào)度和通信示例,它創(chuàng)建了多個(gè)子進(jìn)程,并使用管道進(jìn)行進(jìn)程間通信,父進(jìn)程通過(guò)隨機(jī)選擇一個(gè)子進(jìn)程來(lái)派發(fā)任務(wù)。
-
創(chuàng)建多個(gè)子進(jìn)程:
- 使用
fork()
函數(shù)創(chuàng)建子進(jìn)程,并使用pipe()
函數(shù)創(chuàng)建管道用于進(jìn)程間通信。 - 父進(jìn)程將每個(gè)子進(jìn)程的 PID 和寫(xiě)端管道文件描述符保存在
slots
向量中。
- 使用
-
子進(jìn)程邏輯:
- 子進(jìn)程關(guān)閉寫(xiě)端,然后進(jìn)入一個(gè)無(wú)限循環(huán),不斷等待命令并執(zhí)行。
- 當(dāng)收到命令時(shí),執(zhí)行對(duì)應(yīng)的命令處理函數(shù),如果收到退出命令則退出循環(huán)并終止子進(jìn)程。
-
父進(jìn)程邏輯:
- 通過(guò)
srand()
來(lái)初始化隨機(jī)數(shù)種子,使得每次運(yùn)行產(chǎn)生的隨機(jī)數(shù)不同。 - 進(jìn)入一個(gè)無(wú)限循環(huán),隨機(jī)選擇一個(gè)任務(wù)和一個(gè)子進(jìn)程,然后將任務(wù)發(fā)送給選定的子進(jìn)程。
- 每次發(fā)送完任務(wù)后,休眠一秒鐘。
- 通過(guò)
-
最后,父進(jìn)程關(guān)閉所有子進(jìn)程的寫(xiě)端,然后回收所有子進(jìn)程的信息。
4. 命名管道
(1)創(chuàng)建和關(guān)閉
?mkfifo() 函數(shù)
mkfifo()
函數(shù)用于創(chuàng)建一個(gè)FIFO(First In First Out)或者稱為命名管道,它允許進(jìn)程之間進(jìn)行通信。下面是關(guān)于 mkfifo()
函數(shù)的詳細(xì)介紹:
函數(shù)原型
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
參數(shù)
-
pathname
:要?jiǎng)?chuàng)建的命名管道的路徑名。 -
mode
:創(chuàng)建命名管道時(shí)設(shè)置的權(quán)限模式,通常以 8 進(jìn)制表示,比如0666
。
返回值
- 若成功,返回值為 0;若失敗,返回值為 -1,并設(shè)置errno來(lái)指示錯(cuò)誤類型。
功能mkfifo()
函數(shù)的作用是在文件系統(tǒng)中創(chuàng)建一個(gè)特殊類型的文件,該文件在外觀上類似于普通文件,但實(shí)際上是一個(gè)FIFO,用于進(jìn)程之間的通信。這種通信方式是單向的,即數(shù)據(jù)寫(xiě)入FIFO的一端,可以從另一端讀取出來(lái),按照先進(jìn)先出的順序。
?創(chuàng)建命名管道
-
包含頭文件:首先需要包含相關(guān)的頭文件,以便使用相關(guān)函數(shù)和數(shù)據(jù)結(jié)構(gòu)。
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
-
調(diào)用
mkfifo()
函數(shù):使用mkfifo()
函數(shù)創(chuàng)建命名管道。該函數(shù)原型如下:int mkfifo(const char *pathname, mode_t mode);
-
pathname
:要?jiǎng)?chuàng)建的命名管道的路徑名。 -
mode
:創(chuàng)建命名管道時(shí)設(shè)置的權(quán)限模式,通常以 8 進(jìn)制表示,比如0666
。
示例代碼:
std::string fifoPath = "/tmp/my_named_pipe"; // 命名管道的路徑名 mkfifo(fifoPath.c_str(), 0666); // 創(chuàng)建權(quán)限為0666的命名管道
-
-
處理返回值:檢查
mkfifo()
的返回值,若返回 0 表示成功創(chuàng)建,若返回 -1 表示創(chuàng)建失敗,并通過(guò)errno
來(lái)獲取具體的錯(cuò)誤信息。
??注意事項(xiàng)
- 路徑名:確保要?jiǎng)?chuàng)建的命名管道路徑名合法且沒(méi)有重復(fù)。
- 權(quán)限模式:根據(jù)實(shí)際需求設(shè)置合適的權(quán)限模式,確保可被需要訪問(wèn)該管道的進(jìn)程所訪問(wèn)。
-
錯(cuò)誤處理:對(duì)
mkfifo()
函數(shù)的返回值進(jìn)行適當(dāng)?shù)腻e(cuò)誤處理,根據(jù)具體的錯(cuò)誤原因進(jìn)行相應(yīng)的處理和日志記錄。
-
示例
下面是一個(gè)簡(jiǎn)單的創(chuàng)建命名管道并處理錯(cuò)誤的示例:
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cerrno>
int main() {
std::string fifoPath = "/tmp/my_named_pipe"; // 命名管道的路徑名
if (mkfifo(fifoPath.c_str(), 0666) == -1) {
if (errno == EEXIST) {
std::cerr << "Named pipe already exists" << std::endl;
} else {
perror("Error creating named pipe");
}
} else {
std::cout << "Named pipe created successfully" << std::endl;
}
return 0;
}
?? 使用命名管道進(jìn)行讀寫(xiě)操作:在打開(kāi)命名管道后,可以通過(guò) read()
或 write()
函數(shù)對(duì)其進(jìn)行讀寫(xiě)操作。
?關(guān)閉命名管道
-
關(guān)閉命名管道:當(dāng)進(jìn)程使用完畢命名管道后,需要調(diào)用
close()
函數(shù)來(lái)關(guān)閉文件描述符,釋放相關(guān)資源。close(fd); // 關(guān)閉命名管道
-
注意事項(xiàng)
- 關(guān)閉順序:如果有多個(gè)文件描述符指向同一個(gè)命名管道,需要依次關(guān)閉這些文件描述符,直到所有相關(guān)資源都得到釋放。
-
示例
下面是一個(gè)簡(jiǎn)單的示例,演示了關(guān)閉命名管道的過(guò)程:
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
int main() {
int fd = open("/tmp/my_named_pipe", O_RDONLY); // 以只讀方式打開(kāi)命名管道
// 進(jìn)行讀取操作...
if (close(fd) == -1) {
perror("Error closing named pipe");
} else {
std::cout << "Named pipe closed successfully" << std::endl;
}
return 0;
}
總之,關(guān)閉命名管道是確保在進(jìn)程使用完畢后釋放相關(guān)資源的重要步驟。通過(guò)調(diào)用 close()
函數(shù)可以關(guān)閉文件描述符,釋放命名管道相關(guān)的資源。
(2)通信方式
-
單向通信:
命名管道提供了一種單向通信的方式,一個(gè)進(jìn)程可以向管道中寫(xiě)入數(shù)據(jù),而另一個(gè)進(jìn)程則可以從管道中讀取數(shù)據(jù)。這種通信方式適用于需要單向數(shù)據(jù)傳輸?shù)膱?chǎng)景。 -
持久性:
命名管道與匿名管道不同之處在于,它以文件的形式存在于文件系統(tǒng)中,具有持久性。即使管道的創(chuàng)建進(jìn)程終止,命名管道仍然存在,其他進(jìn)程可以繼續(xù)使用該管道進(jìn)行通信。 -
阻塞和非阻塞:
在進(jìn)行命名管道通信時(shí),可以選擇阻塞或非阻塞模式。在阻塞模式下,如果讀取進(jìn)程嘗試從空管道中讀取數(shù)據(jù),它將被阻塞直到有數(shù)據(jù)可讀;而在非阻塞模式下,讀取進(jìn)程將立即返回一個(gè)錯(cuò)誤,從而避免阻塞。
(3)用法示例
下面是一個(gè)簡(jiǎn)單的示例,演示了兩個(gè)進(jìn)程通過(guò)命名管道進(jìn)行通信的方式:
進(jìn)程 A 寫(xiě)入數(shù)據(jù)到命名管道
int fd = open("/tmp/my_named_pipe", O_WRONLY); // 以只寫(xiě)方式打開(kāi)命名管道
write(fd, "Hello, named pipe!", 18); // 向管道中寫(xiě)入數(shù)據(jù)
close(fd); // 關(guān)閉命名管道
進(jìn)程 B 從命名管道讀取數(shù)據(jù)
int fd = open("/tmp/my_named_pipe", O_RDONLY); // 以只讀方式打開(kāi)命名管道
char buffer[50];
read(fd, buffer, 50); // 從管道中讀取數(shù)據(jù)
close(fd); // 關(guān)閉命名管道
(4)命名管道的特點(diǎn)
-
持久性:命名管道以文件的形式存在于文件系統(tǒng)中,并且具有持久性。即使創(chuàng)建了命名管道的進(jìn)程終止,該管道仍然存在于文件系統(tǒng)中,其他進(jìn)程可以繼續(xù)使用它進(jìn)行通信。
-
單向通信:命名管道提供單向通信的能力,允許一個(gè)進(jìn)程向管道中寫(xiě)入數(shù)據(jù),而另一個(gè)進(jìn)程則可以從管道中讀取數(shù)據(jù)。這種單向通信模式適用于需要單向數(shù)據(jù)傳輸?shù)膱?chǎng)景。
-
實(shí)時(shí)數(shù)據(jù)傳輸:命名管道允許實(shí)時(shí)的數(shù)據(jù)傳輸,寫(xiě)入管道的數(shù)據(jù)會(huì)立即被讀取進(jìn)程獲取,從而實(shí)現(xiàn)了實(shí)時(shí)通信的能力。
-
阻塞和非阻塞模式:對(duì)于讀取和寫(xiě)入操作,命名管道可以選擇阻塞或非阻塞模式。在阻塞模式下,讀取進(jìn)程將被阻塞直到有數(shù)據(jù)可讀,而在非阻塞模式下,讀取進(jìn)程將立即返回錯(cuò)誤,避免阻塞。
-
簡(jiǎn)單易用:使用命名管道進(jìn)行進(jìn)程間通信相對(duì)簡(jiǎn)單,只需通過(guò)類似文件操作的方式打開(kāi)、讀取和關(guān)閉管道即可完成通信過(guò)程。
-
適用范圍廣泛:命名管道適用于各種場(chǎng)景,例如實(shí)現(xiàn)多個(gè)進(jìn)程之間的數(shù)據(jù)共享、進(jìn)程之間的控制和協(xié)調(diào)等。
5. 匿名管道與命名管道的區(qū)別
匿名管道和命名管道分別適用于不同的通信需求。
?匿名管道適用于有親緣關(guān)系的父子進(jìn)程間的通信。
?命名管道更適合不相關(guān)進(jìn)程間的通信,且具有持久性和更靈活的應(yīng)用方式。
1. 匿名管道:
- 單向通信:匿名管道只能支持單向通信,即數(shù)據(jù)只能從一個(gè)進(jìn)程流向另一個(gè)進(jìn)程,無(wú)法實(shí)現(xiàn)雙向通信。
- 存在于內(nèi)存中:匿名管道存在于內(nèi)存中,并且只能用于相關(guān)進(jìn)程之間的通信。一旦相關(guān)進(jìn)程終止,管道也會(huì)自動(dòng)被銷毀。
- 只能用于父子進(jìn)程間通信:匿名管道通常用于父子進(jìn)程之間的通信,因?yàn)樗笸ㄐ诺倪M(jìn)程具有一定的親緣關(guān)系。
- 通常用于shell命令間的通信:在Unix/Linux系統(tǒng)中,匿名管道經(jīng)常用于將一個(gè)命令的輸出傳遞給另一個(gè)命令作為輸入。
2. 命名管道:
- 持久性:命名管道以文件的形式存在于文件系統(tǒng)中,具有持久性,即使創(chuàng)建管道的進(jìn)程終止,管道依然存在,其他進(jìn)程也可以訪問(wèn)和使用它。
- 可用于不相關(guān)的進(jìn)程通信:命名管道可以用于不相關(guān)的進(jìn)程之間的通信,這些進(jìn)程可以位于不同的終端或主機(jī)上。
- 支持阻塞和非阻塞模式:命名管道可以選擇阻塞或非阻塞模式進(jìn)行讀寫(xiě)操作。
- 適用于多種場(chǎng)景:命名管道適用于需要不相關(guān)進(jìn)程之間進(jìn)行通信的各種場(chǎng)景,例如進(jìn)程之間的數(shù)據(jù)共享、控制和協(xié)調(diào)等。
溫馨提示
感謝您對(duì)博主文章的關(guān)注與支持!如果您喜歡這篇文章,可以點(diǎn)贊、評(píng)論和分享給您的同學(xué),這將對(duì)我提供巨大的鼓勵(lì)和支持。另外,我計(jì)劃在未來(lái)的更新中持續(xù)探討與本文相關(guān)的內(nèi)容。我會(huì)為您帶來(lái)更多關(guān)于Linux以及C++編程技術(shù)問(wèn)題的深入解析、應(yīng)用案例和趣味玩法等。如果感興趣的話可以關(guān)注博主的更新,不要錯(cuò)過(guò)任何精彩內(nèi)容!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-752864.html
再次感謝您的支持和關(guān)注。我們期待與您建立更緊密的互動(dòng),共同探索Linux、C++、算法和編程的奧秘。祝您生活愉快,排便順暢!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-752864.html
到了這里,關(guān)于【探索Linux】—— 強(qiáng)大的命令行工具 P.14(進(jìn)程間通信 | 匿名管道 | |進(jìn)程池 | pipe() 函數(shù) | mkfifo() 函數(shù))的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!