丹陽(yáng)做公司網(wǎng)站sem優(yōu)化師
目錄
進(jìn)程間通信
什么是進(jìn)程間通信
進(jìn)程間通信的一般規(guī)律
前言:
管道
代碼預(yù)準(zhǔn)備:
如何創(chuàng)建管道 -- pipe 函數(shù)
參數(shù):
返回值:
wait 函數(shù)
參數(shù):
驗(yàn)證管道的運(yùn)行:
源文件 test.c :
makefile 文件:
?運(yùn)行結(jié)果:
進(jìn)程間通信
什么是進(jìn)程間通信
進(jìn)程間通信(Inter-Process Communication, IPC)是操作系統(tǒng)中非常重要的一個(gè)概念,它指的是不同進(jìn)程之間進(jìn)行數(shù)據(jù)交換或者傳遞消息的機(jī)制。
進(jìn)程間通信的主要原因和目的是:
資源共享:不同的進(jìn)程可能需要訪問(wèn)相同的資源或數(shù)據(jù),例如文件、數(shù)據(jù)庫(kù)等。通過(guò)IPC,可以實(shí)現(xiàn)對(duì)這些共享資源的有效管理和同步訪問(wèn)。
任務(wù)協(xié)作:在很多情況下,一個(gè)復(fù)雜的任務(wù)可能被分解為多個(gè)子任務(wù),由不同的進(jìn)程來(lái)執(zhí)行。為了完成整個(gè)任務(wù),這些進(jìn)程之間需要相互通信,以協(xié)調(diào)它們的工作流程。
提高效率:對(duì)于一些計(jì)算密集型的任務(wù),可以通過(guò)將工作分配給多個(gè)進(jìn)程來(lái)并行處理,從而加速任務(wù)的完成。這時(shí)就需要有效的通信機(jī)制來(lái)保證各部分工作的正確性與一致性。
?模塊化設(shè)計(jì):軟件開(kāi)發(fā)時(shí)采用模塊化的設(shè)計(jì)思想,即將程序劃分為相對(duì)獨(dú)立但又能相互作用的功能單元(即進(jìn)程)。這樣做不僅有利于維護(hù),而且也使得系統(tǒng)更加靈活可擴(kuò)展。良好的IPC支持能夠促進(jìn)這種架構(gòu)模式的應(yīng)用。
跨網(wǎng)絡(luò)服務(wù)調(diào)用:隨著分布式系統(tǒng)的普及,在不同主機(jī)上的進(jìn)程也需要能夠互相通信。這涉及到更高級(jí)別的IPC形式,如RPC (Remote Procedure Call) 等技術(shù)。
進(jìn)程間通信的一般規(guī)律
讓不同的進(jìn)程看到同一份資源!!!
前言:
假設(shè)現(xiàn)在有A、B進(jìn)程,在A進(jìn)程中開(kāi)辟一塊空間并寫入數(shù)據(jù),讓 B 進(jìn)程去 A 進(jìn)程的這塊空間讀取數(shù)據(jù),雖然確實(shí)讓不同的進(jìn)程看到了同一份資源,但是破壞了進(jìn)程的獨(dú)立性。
所以進(jìn)程間通信需要有交換數(shù)據(jù)的空間,且這塊空間不能由通信雙方任何一個(gè)提供,那么這塊空間只能由操作系統(tǒng)提供。
我們回顧一下父子進(jìn)程,假設(shè)父進(jìn)程對(duì)同一個(gè)文件分別用讀方式和寫方式打開(kāi),父進(jìn)程將會(huì)得到兩個(gè)文件描述符對(duì)象。
為什么對(duì)同一個(gè)文件分別用讀方式打開(kāi)和寫方式打開(kāi),會(huì)創(chuàng)建兩個(gè)文件描述符對(duì)象?
當(dāng)你使用讀取模式(例如?open("file.txt", "r")
)和寫入模式(例如?open("file.txt", "w")
)分別打開(kāi)同一個(gè)文件時(shí),操作系統(tǒng)會(huì)為每次打開(kāi)操作分配一個(gè)獨(dú)立的文件描述符。這樣做有幾個(gè)原因:
獨(dú)立性:每個(gè)文件描述符代表了對(duì)文件的一個(gè)獨(dú)立訪問(wèn)路徑。這意味著你可以同時(shí)從一個(gè)文件描述符讀取數(shù)據(jù),而從另一個(gè)文件描述符寫入數(shù)據(jù),即使它們指向的是同一個(gè)物理文件。這種獨(dú)立性允許更靈活地處理文件。
位置指針:每個(gè)文件描述符都有自己的文件偏移量或位置指針。當(dāng)你通過(guò)不同的文件描述符讀寫文件時(shí),每個(gè)描述符的位置指針可以獨(dú)立移動(dòng)。這樣,在進(jìn)行多線程或多進(jìn)程操作時(shí),各個(gè)進(jìn)程/線程可以安全地在不同位置上工作而不互相干擾。
權(quán)限控制:以不同模式打開(kāi)文件提供了對(duì)文件的不同級(jí)別的訪問(wèn)權(quán)限。比如,只讀模式下你只能讀取文件內(nèi)容,而在寫入模式下還可以修改文件。擁有兩個(gè)文件描述符意味著可以根據(jù)需要選擇適當(dāng)?shù)脑L問(wèn)級(jí)別,同時(shí)也增加了安全性,因?yàn)椴恍枰o所有操作都賦予完全相同的權(quán)限。
性能與資源管理:盡管是同一份文件,但根據(jù)具體的操作需求(如順序讀取、隨機(jī)寫入等),操作系統(tǒng)可能采取不同的策略來(lái)優(yōu)化I/O性能。此外,維護(hù)多個(gè)文件描述符也便于系統(tǒng)更好地跟蹤哪些程序正在使用該文件,并且有助于實(shí)現(xiàn)諸如引用計(jì)數(shù)這樣的機(jī)制,從而有效地管理文件相關(guān)的系統(tǒng)資源。
總之,雖然這兩個(gè)文件描述符對(duì)應(yīng)于同一物理文件,但是它們各自保持了自己的狀態(tài)信息,這使得在同一時(shí)間內(nèi)能夠執(zhí)行更加復(fù)雜的并發(fā)操作,同時(shí)也增強(qiáng)了系統(tǒng)的靈活性和安全性。
父進(jìn)程得到兩個(gè)文件描述符對(duì)象之后,我們創(chuàng)建子進(jìn)程,子進(jìn)程繼承父進(jìn)程的文件描述符表,父子進(jìn)程指向同一個(gè)文件和緩沖區(qū)!這也就實(shí)現(xiàn)了父子進(jìn)程看到同一份資源,就可以實(shí)現(xiàn)進(jìn)程間通信!
管道
從前言中就可以看出,管道的本質(zhì)是文件!
在 Linux 中,管道(pipe)是一種進(jìn)程間通信(IPC, Inter-Process Communication)的機(jī)制,它允許一個(gè)進(jìn)程的輸出直接作為另一個(gè)進(jìn)程的輸入。
管道可以看作是連接兩個(gè)或多個(gè)命令的數(shù)據(jù)流通道,它使得數(shù)據(jù)可以在不同的程序之間流動(dòng)而不需要通過(guò)臨時(shí)文件。
標(biāo)準(zhǔn)的管道是單向的,即數(shù)據(jù)只能從寫端流向讀端。
匿名管道:?
在前言中,父進(jìn)程和子進(jìn)程的文件的讀端和寫端都是打開(kāi)的,為了符合管道是單向的,我們可以選擇讓 父進(jìn)程作為寫端,子進(jìn)程作為讀端 或者 父進(jìn)程作為讀端、子進(jìn)程作為寫端!
如下圖,我們讓父進(jìn)程作為寫端,子進(jìn)程作為讀端:
代碼預(yù)準(zhǔn)備:
如何創(chuàng)建管道 -- pipe 函數(shù)
#include <unistd.h>int pipe(int pipefd[2]);
該函數(shù)用于創(chuàng)建一個(gè)匿名管道。
參數(shù):
pipefd
:這是一個(gè)指向兩個(gè)整數(shù)的指針。pipe()
?成功后,這兩個(gè)整數(shù)會(huì)被設(shè)置為新創(chuàng)建的管道的讀端和寫端的文件描述符。讀端通常為fd[0]
,寫端通常為fd[1]
。
返回值:
- 它在成功時(shí)返回 0,并且通過(guò)其參數(shù)(一個(gè)包含兩個(gè)整數(shù)的數(shù)組)來(lái)傳遞兩個(gè)文件描述符;
- 如果調(diào)用失敗,
pipe()
會(huì)返回-1,并設(shè)置全局變量errno
來(lái)指示具體的錯(cuò)誤原因。
wait 函數(shù)
#include <sys/types.h>
#include <sys/wait.h>pid_t wait(int *status);
wait()
函數(shù)是 Unix 和 Linux 系統(tǒng)中用于進(jìn)程控制的一個(gè)重要函數(shù)。它允許一個(gè)進(jìn)程(通常是父進(jìn)程)等待其子進(jìn)程結(jié)束,并獲取子進(jìn)程的退出狀態(tài)。wait()
函數(shù)會(huì)阻塞調(diào)用者,直到至少有一個(gè)子進(jìn)程終止或接收到一個(gè)信號(hào)。
參數(shù):
status
:這是一個(gè)指向整數(shù)的指針,用來(lái)存儲(chǔ)子進(jìn)程的退出狀態(tài)信息。如果不需要這個(gè)信息,可以傳遞?NULL
。
返回值:
- 如果有子進(jìn)程成功終止,則返回該子進(jìn)程的 PID;
- 如果沒(méi)有子進(jìn)程或者所有子進(jìn)程都還在運(yùn)行,
wait()
?將一直阻塞,直到至少有一個(gè)子進(jìn)程終止。- 如果發(fā)生錯(cuò)誤(如被信號(hào)中斷),則返回-1,并設(shè)置?
errno
。
驗(yàn)證管道的運(yùn)行:
源文件 test.c :
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>void writer(int wfd)
{const char *str="hello father,I am child";char buffer[128];int cnt=0;pid_t pid=getpid();//獲得進(jìn)程pidwhile(1){//向緩沖區(qū)里寫入內(nèi)容snprintf(buffer,sizeof(buffer),"message:%s,pid:%d,count:%d\n",str,pid,cnt);//把緩沖區(qū)里的內(nèi)容寫入到管道write(wfd,buffer,sizeof(buffer));cnt++;sleep(1);}
}void reader(int rfd)
{char buffer[128];while(1){//讀取管道里的內(nèi)容ssize_t n=read(rfd,buffer,sizeof(buffer)-1);printf("father get a message: %s",buffer);}
}int main()
{int pipefd[2];int n=pipe(pipefd);if(n<0){return 1;}printf("%d %d\n",pipefd[0],pipefd[1]);pid_t id=fork();if(id==0){//子進(jìn)程創(chuàng)建成功//關(guān)閉讀端close(pipefd[0]);writer(pipefd[1]);//寫exit(0);}//父進(jìn)程關(guān)閉寫端close(pipefd[1]);reader(pipefd[0]);//讀wait(NULL);return 0;
}
makefile 文件:
testpipe:test.cgcc -o $@ $^.PHONY:clean
clean:rm -f testpipe
?運(yùn)行結(jié)果:
從下面的運(yùn)行結(jié)果可以看出,父進(jìn)程接收到了子進(jìn)程寫的數(shù)據(jù):