無名管道應用的乙個重大限制是它沒有名字,因此,只能用於具有親緣關係的程序間通訊,在有名管道(named pipe或fifo)提出後,該限制得到了克服。fifo不同於管道之處在於它提供乙個路徑名與之關聯,以fifo的檔案形式存在於檔案系統中。這樣,即使與fifo的建立程序不存在親緣關係的程序,只要可以訪問該路徑,就能夠彼此通過fifo相互通訊(能夠訪問該路徑的程序以及fifo的建立程序之間),因此,通過fifo不相關的程序也能交換資料。值得注意的是,fifo嚴格遵循先進先出(first in first out),對管道及fifo的讀總是從開始處返回資料,對它們的寫則把資料新增到末尾。它們不支援諸如lseek()等檔案定位操作。
管道的緩衝區是有限的
(管道制存在於記憶體中,在管道建立時,為緩衝區分配乙個頁面大小)
管道所傳送的是
無格式位元組流
,這就要求管道的讀出方和寫入方必須事先約定好資料的格式,比如多少位元組算作乙個訊息(或命令、或記錄)等等
fifo往往都是多個寫程序,乙個讀程序。
fifo的開啟規則:
如果當前開啟操作是為讀而開啟fifo時,若已經有相應程序為寫而開啟該fifo,則當前開啟操作將成功返回;否則,可能阻塞直到有相應程序為寫而開啟該fifo(當前開啟操作設定了阻塞標誌);或者,成功返回(當前開啟操作沒有設定阻塞標誌)。
如果當前開啟操作是為寫而開啟fifo時,如果已經有相應程序為讀而開啟該fifo,則當前開啟操作將成功返回;否則,可能阻塞直到有相應程序為讀而開啟該fifo(當前開啟操作設定了阻塞標誌);或者,返回enxio錯誤(當前開啟操作沒有設定阻塞標誌)。
總之就是一句話,一旦設定了阻塞標誌,呼叫mkfifo建立好之後,那麼管道的兩端讀寫必須分別開啟,有任何一方未開啟,則在呼叫open的時候就阻塞。
約定:如果乙個程序為了從fifo中讀取資料而阻塞開啟fifo,那麼稱該程序內的讀操作為設定了阻塞標誌的讀操作。(意思就是我現在要開啟乙個有名管道來讀資料!)
如果有程序寫開啟fifo,且當前fifo內沒有資料(可以理解為管道的兩端都建立好了,但是寫端還沒開始寫資料!)
則對於設定了阻塞標誌的讀操作來說,將一直阻塞(就是block住了,等待資料。它並不消耗cpu資源,這種程序的同步方式對cpu而言是非常有效率的。)
對於沒有設定阻塞標誌讀操作來說則返回-1,當前errno值為eagain,提醒以後再試。
對於設定了阻塞標誌的讀操作說(見上面的約定)
造成阻塞的原因有兩種
fifo內有資料,但有其它程序在讀這些資料
fifo內沒有資料。解阻塞的原因則是fifo中有新的資料寫入,不論信寫入資料量的大小,也不論讀操作請求多少資料量。
讀開啟的阻塞標誌只對本程序第乙個讀操作施加作用,如果本程序內有多個讀操作序列,則在第乙個讀操作被喚醒並完成讀操作後,其它將要執行的讀操作將不再阻塞,即使在執行讀操作時,fifo中沒有資料也一樣,此時,讀操作返回0。
注:如果fifo中有資料,則設定了阻塞標誌的讀操作不會因為fifo中的位元組數小於請求讀的位元組數而阻塞,此時,讀操作會返回fifo中現有的資料量。
約定:如果乙個程序為了向fifo中寫入資料而阻塞開啟fifo,那麼稱該程序內的寫操作為設定了阻塞標誌的寫操作。
對於設定了阻塞標誌的寫操作:
當要寫入的資料量不大於pipe_buf時,linux將保證寫入的原子性。如果此時管道空閒緩衝區不足以容納要寫入的位元組數,則進入睡眠,直到當緩衝區中能夠容納要寫入的位元組數時,才開始進行一次性寫操作。(pipe_buf ==>> /usr/include/linux/limits.h)
當要寫入的資料量大於pipe_buf時,linux將不再保證寫入的原子性。fifo緩衝區一有空閒區域,寫程序就會試圖向管道寫入資料,寫操作在寫完所有請求寫的資料後返回。
對於沒有設定阻塞標誌的寫操作:
當要寫入的資料量大於pipe_buf時,linux將不再保證寫入的原子性。在寫滿所有fifo空閒緩衝區後,寫操作返回。
當要寫入的資料量不大於pipe_buf時,linux將保證寫入的原子性。如果當前fifo空閒緩衝區能夠容納請求寫入的位元組數,寫完後成功返回;如果當前fifo空閒緩衝區不能夠容納請求寫入的位元組數,則返回eagain錯誤,提醒以後再寫;
簡單描述下上面設定了阻塞標誌的邏輯
設定了阻塞標誌
if (buf_to_write <= pipe_buf) //寫入的資料量不大於pipe_buf時
then
if ( buf_to_write > system_buf_left ) //保證寫入的原子性,要麼一次性把buf_to_write全都寫完,要麼乙個位元組都不寫!
then
block ;
until ( buf_to_write <= system_buf_left );
goto write ;
else
write ;
fielse
write ; //不管怎樣,就是不斷寫,知道把緩衝區寫滿了才阻塞
fi
#include #include #include #include #include #include #include #define fifo_name "/tmp/my_fifo"
#define buffer_size pipe_buf
int main()
while(res > 0);
close(pipe_fd);
} else
printf("process %d finished, %d bytes read\n", getpid(), bytes);
exit(exit_success);
}
#include #include #include #include #include #include #include #define fifo_name "/tmp/my_fifo"
#define buffer_size pipe_buf
#define ten_meg (1024 * 100)
int main()
} printf("process %d opening fifo o_wronly\n", getpid());
pipe_fd = open(fifo_name, open_mode);
printf("process %d result %d\n", getpid(), pipe_fd);
//sleep(20);
if (pipe_fd != -1)
bytes += res;
printf("%d\n",bytes);
} close(pipe_fd);
} else
printf("process %d finish\n", getpid());
exit(exit_success);
}
linux系統中的有名管道(FIFO)
無名管道應用的乙個重大限制是它沒有名字,因此,只能用於具有親緣關係的程序間通訊,在有名管道 named pipe或fifo 提出後,該限制得到了克服。fifo不同於管道之處在於它提供乙個路徑名與之關聯,以fifo的檔案形式存在於檔案系統中。這樣,即使與fifo的建立程序不存在親緣關係的程序,只要可以...
Linux 有名管道
include apue.h 在當前目錄建立乙個管道檔案 main printf success to mkfifo ret d n ret return 0 include apue.h main printf success to open file fd d n fd 向有名管道中寫資料 wr...
Linux有名管道程式設計
有名管道可以用於任何兩個程式間通訊,因為有名字可引用。注意管道都是單向的,因此雙方通訊需要兩個管道。下面分別是這兩個程式 同樣是lucy先執行,然後是peter。fifolucy.c include include include include include include include in...