程序通訊(無名管道)的簡單記錄

2021-10-08 04:21:33 字數 4461 閱讀 3795

例項演示

unix系統提供有名管道和無名管道兩種資料通訊方式。無名管道只能在有共同祖先(有親緣關係)的程序間使用,有名管道可以在無親緣關係的程序間使用。管道普遍存在於shell中。

無名管道為建立管道的程序及其子孫提供一條以位元流方式傳送訊息的通訊管道,該管道在邏輯上被看作管道檔案,在物理上則由檔案系統的高速緩衝區構成,而很少啟動外設。管道按fifo(先進先出)方式傳送訊息,且只能單向傳送訊息。如果需要父程序向子程序、子程序向父程序雙向傳遞,可以設定兩條管道。

write()和read()函式都是系統呼叫,我們熟知的檔案讀寫操作fwrite()和fread()都是通過write()和read()來實現的。

區別在於read()每次讀的資料是呼叫者要求的大小,且read()從核心緩衝區(作業系統開闢的一段空間用來儲存磁碟上的資料)讀取資料,所以每次呼叫read()會涉及到使用者態與核心態之間的切換從而損耗一定的效能。而fread()每次都會從核心緩衝區讀比要求更多的資料,然後放到應用程序緩衝區(首位址存在file結構體中),這樣下次再讀資料只需要到應用程序緩衝區中去取而無需過多的系統呼叫。

同理,write()每次寫的資料是呼叫者要求的大小,write()將資料寫到核心緩衝區中,依然涉及到使用者態與核心態之間的切換,作業系統會定期地把這些存在核心緩衝區的資料寫回磁碟中。而fwrite每次都會先把資料寫入乙個應用程序緩衝區,等到該緩衝區滿了,或者呼叫類似呼叫fflush這種沖洗緩衝區的函式時,系統會呼叫write一次性把相應資料寫進核心緩衝區中。同樣減少了系統呼叫。

實際上write和read不會直接從磁碟檔案中讀寫資料。例如read是從磁碟所關聯的乙個核心緩衝區讀寫資料。(因為磁碟讀取資料速度實在太慢了,所以作業系統往往採用預讀技術讀取磁碟資料)。write也是僅將資料寫進核心緩衝區,作業系統通過執行乙個守護程序,定期的將核心緩衝區寫入磁碟。

// include 

intwrite

(int handle,

void

*buf, size_t len)

/*將緩衝區的資料寫入與handle相聯的檔案或裝置中,handle是從creat、open、dup或dup2呼叫中得到的檔案控制代碼。寫入成功時返回寫的位元組數,錯誤時返回-1

*/int

read

(int handle,

void

*buf, size_t len)

/*從檔案控制代碼handle所指向的檔案中讀取資料到所指向的快取區中,讀取成功時返回值為實際讀取的位元組數

*/

利用unix系統提供的系統呼叫pipe(),可以建立一條單向同步通訊管道。

// int pipe(int *fd)

#include

int fd[2]

;pipe

(fd)

;

其中fd[1]為寫入端,fd[0]為讀出端

###fork()函式

fork()函式通過系統呼叫建立乙個與原來程序幾乎完全相同的程序,也就是兩個程序可以做完全相同的事,但如果初始引數或者傳入的變數不同,兩個程序也可以做不同的事。乙個程序呼叫fork()函式後,系統先給新的程序分配資源,例如儲存資料和**的空間。然後把原來的程序的所有值都複製到新的新程序中,只有少數值與原來的程序的值不同。相當於轉殖了乙個自己。

兩個程序執行沒有固定的先後順序,哪個程序先執行要看系統的程序排程策略,且fork()是把程序當前的情況拷貝乙份,建立子程序後,從fork()後繼續執行

fork()函式僅僅呼叫一次,但可以理解為返回兩次

可以將父子程序理解為鍊錶,父程序指向子程序,子程序沒有新的子程序,指向0

wait()函式用於使父程序(也就是呼叫wait()的程序)阻塞,直到乙個子程序結束或該程序接收到乙個指定的訊號為止。如果該父程序沒有子程序或它的子程序已經結束,則wait()就會立即返回。

#include

pit_d wait

(int

*status);/*

status是乙個整型指標,是該子程序退出的狀態,如exit(0)、exit(1)等,status 可以設成null

如果執行成功則返回子程序識別碼(pid), 如果有錯誤發生則返回-1

*/

###waitpid()函式

waitpid()函式並不一定要等待乙個終止的子程序,它還有若干選項,wait()函式只是waitpid()函式的乙個特例。

#include

pid_t waitpid

(pid_t pid,

int*status,

int options);/*

pid > 0,只等待程序id等於pid的子程序,不管其他子程序是否結束

pid = -1,等待任何乙個子程序退出,此時和wait作用相同

pid = 0,等待其組 id 等於呼叫程序的組 id 的任一子程序

pid < -1,等待其組 id 等於 pid 的絕對值的任一子程序

status,作用同wait()

options:

0,同wait(),阻塞父程序,等待子程序退出

wnohang:若由 pid 指定的子程序沒有結束,則 waitpid()不阻塞而立即返回。此時返回值為0

wuntraced:為了實現某種操作,由pid指定的任一子程序已被暫停,且其狀態自暫停依賴還未報告過,則返回其狀態

返回值:

正常執行,返回子程序識別碼(pid)

使用wnohang且沒有子程序退出,返回0

呼叫出錯返回-1

*/

exit()用於結束當前程序/當前程式,在整個程式中,只要呼叫exit(),即結束程式。

exit(0)表示正常退出;

exit(x)(x不為0)都表示異常退出,這個x是返回給作業系統(包括unix,linux,和ms dos)的,以供其他程式使用。

與return的區別:

按照ansi c,在最初呼叫的main()中使用return和exit()的效果相同。但要注意這裡所說的是"最初呼叫"。如果main()在乙個遞迴程式中,exit()仍然會終止程式;但return將控制權移交給遞迴的前一級,直到最初的那一級,此時return才會終止程式。return和exit()的另乙個區別在於,即使在除main()之外的函式中呼叫exit(),它也將終止程式。

#include

exit(0

);

其與exit()功能類似,作用為直接使程序停止執行,清除其使用的記憶體空間,並銷毀其在核心中的各種資料結構。而exit()則在退出前加了若干道工序, exit()函式在呼叫exit這一系統呼叫之前要檢查檔案的開啟情況,把檔案緩衝區中的內容寫回檔案。

#include

_exit(0

);

#include

#include

#include

intmain

(int argc,

char

*ar**)

else

return0;

}//result : this is an example

生成兩個子程序,父程序來讀取

#include

#include

#include

intmain

(int argc,

char

*ar**)

else

wait(0

);if(

(r =

read

(fd[0]

, s,50)

)==-1

)else

wait(0

);if(

(r =

read

(fd[0]

, s,50)

)==-1

)else

exit(0

);}return0;

}/*result:

child process p1

child process p2

child process p1 is sending messages

child process p2 is sending messages

*/

程序通訊 無名管道

管道是單向的 先進先出的,它把乙個程序的輸出和另乙個程序的輸入連線在一起。管道包括無名管道和有名管道兩種,前者用於父程序和子程序間的通訊,後者可用於執行於同一系統中的任意兩個程序間的通訊。乙個程序 寫程序 在管道的尾部寫入資料,另乙個程序 讀程序 從管道的頭部讀出資料。管道提供了簡單的流控制機制,程...

linux程序通訊 無名管道

linux無名管道通訊特點無名管道是半雙工的通訊方式,資料只能一方傳送,另一方接收。無名管道只適用於親緣關係的程序通訊。資料的讀出和寫入 乙個程序向管道中寫的內容被管道另一端的程序讀出。寫入的內容每次都新增在管道緩衝區的末尾,並且每次都是從緩衝區的頭部讀出資料。include include inc...

程序間通訊 無名管道

在上次的部落格中,我給大家介紹了程序間通訊的方式 有名管道。管道分為有名管道和無名管道,那麼此次我將給大家介紹一下另一種管道通訊 無名管道。有名管道是可以應用於任何兩個程序之間資料的單向傳遞,而無名管道是相對於有名管道的,無名管道在使用時產生,不使用後釋放,並不會在系統上留下任何痕跡。無名管道因其使...