在介紹管道之前,我們先了解一下程序間通訊。
程序間通訊目的:
程序間通訊的分類
本篇部落格將著重介紹管道。
什麼是管道?
匿名管道
#include
.h>
功能:建立一無名管道
原型:int
pipe(int
fd[2]);
引數,fd檔案描述符陣列,fd
[0]表示讀端,fd
[1]表示寫段
返回值:成功返回0,失敗返回錯誤**
舉個栗子:
從鍵盤讀取資料,寫入管道,讀取管道,寫到螢幕
#include
#include
#include
#include
int main()
//read from stdin
while(fgets(buf, 100, stdin))
memset(buf, 0x00, sizeof(buf));
//read from pipe
if((len = read(fds[0], buf, 100)) == -1)
// write into stdout
if(write(1, buf, len) != len)}}
write函式介紹
標頭檔案:#include
write函式有兩種用法。一種是:ssize_t write(int fd, const void *buf, size_t nbyte);
fd:檔案描述符;
buf:指定的緩衝區,即指標,指向一段記憶體單元;
nbyte:要寫入檔案指定的位元組數;
返回值:寫入文件的位元組數(成功);-1(出錯)
write函式把buf中nbyte寫入檔案描述符handle所指的文件,成功時返回寫的位元組數,錯誤時返回-1。
另一種是: write(const char* str,int n)
str是字元指標或字元陣列,用來存放乙個字串。n是int型數,
它用來表示輸出顯示字串中字元的個數。
read函式介紹
read()會把引數fd所指的檔案傳送nbyte個位元組到buf指標所指的記憶體中。
若引數nbyte為0,則read()不會有作用並返回0。返回值為實際讀取到的位元組數。
perror函式介紹
perror(s) 用來將上乙個函式發生錯誤的原因輸出到標準裝置(stderr)。引數 s 所指的字串會先列印出,後面再加上錯誤原因字串。此錯誤原因依照全域性變數errno的值來決定要輸出的字串。在庫函式中有個errno變數,每個errno值對應著以字串表示的錯誤型別。當你呼叫"某些"函式出錯時,該函式已經重新設定了errno的值。perror函式只是將你輸入的一些資訊和現在的errno所對應的錯誤一起輸出。
用fork來共享管道原理
//這個巨集定義的寫法相當新穎
#define err_exit(m) \
do \
while(0)
int main()
pid_t pid;
pid = fork();
if(pid == -1)
if(pid == 0)
// close(pipefd[1]);
exit(exit_success);
}close(pipefd[1]);
char buf[30] = ;
while(1)
return
0;}管道的讀寫規則
當沒有資料可讀時
o_nonblock disable:read 呼叫阻塞,即程序暫停執行,一直等到有資料來為止。
o_nonblock enable:read 呼叫返回-1,errno值為eagain。
當管道滿時
o_nonblock disable: write呼叫阻塞,直到有程序讀走資料。
o_nonblock enable:呼叫返回-1,errno值為eagain。
如果所有管道寫端對應的檔案描述符被關閉,read返回0。
如果所有管道讀端對應的檔案描述符被關閉,則write操作會產生訊號sigpipe,進而可能導致write程序退出。
當要寫入的資料量不大於pipe_buf時,linux將保證寫入的原子性。
當要寫入的資料量大於pipe_buf時,linux不在保證寫入的原子性。
原子性
栗子:
a想要從自己的帳戶中轉1000塊錢到b的帳戶裡。那個從a開始轉帳,到轉帳結束的這乙個過程,稱之為乙個事務。在這個事務裡,要做如下操作:
1. 從a的帳戶中減去1000塊錢。如果a的帳戶原來有3000塊錢,現在就變成2000塊錢了。
2. 在b的帳戶裡加1000塊錢。如果b的帳戶如果原來有2000塊錢,現在則變成3000塊錢了。
如果在a的帳戶已經減去了1000塊錢的時候,忽然發生了意外,比如停電什麼的,導致轉帳事務意外終止了,而此時b的帳戶裡還沒有增加1000塊錢。那麼,我們稱這個操作失敗了,要進行回滾。回滾就是回到事務開始之前的狀態,也就是回到a的帳戶還沒減1000塊的狀態,b的帳戶的原來的狀態。此時a的帳戶仍然有3000塊,b的帳戶仍然有2000塊。
我們把這種要麼一起成功(a帳戶成功減少1000,同時b帳戶成功增加1000),要麼一起失敗(a帳戶回到原來狀態,b帳戶也回到原來狀態)的操作叫原子性操作。
如果把乙個事務可看作是乙個程式,它要麼完整的被執行,要麼完全不執行。這種特性就叫原子性。
管道的特點
命名管道
建立乙個命名管道
1. 命名管道可以在命令列上建立,命令列方法是使用下面這個命令:
$mkfifo filename
2.命名管道也可以從程式裡建立
int mkfifo(const
char* filename,mode_t mode);
建立命名管道:
int main(int argc,char *argv)
匿名管道與命名管道的區別命名管道的開啟規則如果當前操作是為讀而開啟fifo時
如果之前開啟操作是為寫而開啟fifo時
程序間通訊之管道篇
這裡我們談談程序間互動的機制,這裡不同於使用訊號來讓程序間傳送訊息。當從乙個程序連線資料流到另乙個程序時,我們使用術語管道 pipe 我們通常是把乙個程序的輸出通過管道連線 到另乙個程序的輸入。我們來看看底層的pipe 函式呼叫。通過這個函式在兩個程式間傳遞資料不需要啟動乙個shell來解釋請求的命...
程序間通訊之管道篇
每個程序各自有不同的使用者位址空間,任何乙個程序的全域性變數在另乙個程序中都是看不到的。所以程序之間如果要交換資料就必須通過核心。在核心中開闢一塊緩衝區,程序1把資料從使用者空間拷到核心緩衝區,程序2再從核心緩衝區把資料讀走,核心提供的這種機制稱為程序間通訊 ipc,interprocess com...
程序間通訊 之 管道
一 無名管道 特點 具有親緣關係的程序間通訊,但不僅僅指父子程序之間哦。1 無名管道的建立 int pipe int pipefd 引數 pipefd 陣列的首位址 返回值 成功返回0,失敗返回 1 注意 無名管道存在核心空間,建立成功會給使用者空間兩個檔案描述符,fd 0 讀管道 fd 1 寫管道...