管道是一種把兩個進程之間的標準輸入和標準輸出連接起來的機制,從而提供一種讓多個進程間通信的方法,當進程創建管道時,每次都需要提供兩個文件描述符來操作管道。其中一個對管道進行寫操作,另一個對管道進行讀操作。對管道的讀寫與一般的IO系統函數一致,使用write()函數寫入數據,使用read()讀出數據。
#include<unistd.h>int pipe(int filedes[2]);
返回值:成功,返回0,否則返回-1。參數數組包含pipe使用的兩個文件的描述符。fd[0]:讀管道,fd[1]:寫管道。
必須在fork()中調用pipe(),否則子進程不會繼承文件描述符。兩個進程不共享祖先進程,就不能使用pipe。但是可以使用命名管道。



當管道進行寫入操作的時候,如果寫入的數據小于128K則是非原子的,如果大于128K字節,緩沖區的數據將被連續地寫入管道,直到全部數據寫完為止,如果沒有進程讀取數據,則將一直阻塞,如下:



在上例程序中,子進程一次性寫入128K數據,當父進程將全部數據讀取完畢的時候,子進程的write()函數才結束阻塞并且
返回寫入信息。
命名管道FIFO
管道最大的劣勢就是沒有名字,只能用于有一個共同祖先進程的各個進程之間。FIFO代表先進先出,單它是一個單向數據流,也就是半雙工,和
管道不同的是:每個FIFO都有一個路徑與之關聯,從而允許無親緣關系的進程訪問。
#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode);
這里pathname是路徑名,mode是sys/stat.h里面定義的創建文件的權限.
有親緣關系進程間的fifo的例子
/* * 有親緣關系的進程間的fifo的使用 * fifo 使用的簡單例子 */#include "../all.h"#define FIFO_PATH "/tmp/hover_fifo"void do_sig(int signo){ if (signo == SIGCHLD) while (waitpid(-1, NULL, WNOHANG) > 0) ;}intmain(void){ int ret; int fdr, fdw; pid_t pid; char words[10] = "123456789"; char buf[10] = {'/0'}; // 創建它,若存在則不算是錯誤, // 若想修改其屬性需要先打開得到fd,然后用fcntl來獲取屬性,然后設置屬性. if (((ret = mkfifo(FIFO_PATH, FILE_MODE)) == -1) && (errno != EEXIST)) perr_exit("mkfifo()"); fprintf(stderr, "fifo : %s created successfully!/n", FIFO_PATH); signal(SIGCHLD, do_sig); pid = fork(); if (pid == 0) { // child if ((fdr = open(FIFO_PATH, O_WRONLY)) < 0) // 打開fifo用來寫 perr_exit("open()"); sleep(2); // 寫入數據 if (write(fdr, words, sizeof(words)) != sizeof(words)) perr_exit("write"); fprintf(stderr, "child write : %s/n", words); close(fdw); } else if (pid > 0) { // parent if ((fdr = open(FIFO_PATH, O_RDONLY)) < 0) // 打開fifo用來讀 perr_exit("open()"); fprintf(stderr, "I father read, waiting for child .../n"); if (read(fdr, buf, 9) != 9) //讀數據 perr_exit("read"); fprintf(stderr, "father get buf : %s/n", buf); close(fdr); } // 到這里fifo管道并沒有被刪除,必須手動調用函數unlink或remove刪除. return 0; }
新聞熱點
疑難解答