Ordinary Pipes(普通管道)允許兩個行程在標準生產者消費者方式下進行通信;生產者從管道的一端[寫入端 (write-end)]寫入,消費者從另一端[讀取端 (read-end)]讀取。以下是普通管道的幾個關鍵特點(來自AI):
單向通訊:
普通管道是單向的,這意味著數據只能從一個進程流向另一個進程。通常,一個進程寫入管道,而另一個進程從管道中讀取數據。
匿名性:
普通管道是匿名的 (anaonymous),這意味著它們不會被命名,並且在創建後只能在父進程和其子進程之間使用。
使用 pipe() 函數:
在 UNIX 系統上,使用 pipe(int fd[]) 函數來建構一個普通管道。這個函數產生一個可透過檔案描述元 (file descriptor) int fd[] 存取的管道:fd[0] 是管道的讀取端,fd[1] 是寫入端。
內存中的緩衝區:
管道在內存中維護一個緩衝區,用於存儲從寫入端寫入的數據,直到這些數據被讀取。
阻塞行為:
如果寫入端的緩衝區已滿,寫入操作會阻塞,直到有空間可用。如果讀取端沒有數據可讀,讀取操作也會阻塞,直到有數據可用。
unix_pipe.c
/**
* Example program demonstrating UNIX pipes.
*
* Figures 3.25 & 3.26
*
* @author Silberschatz, Galvin, and Gagne
* Operating System Concepts - Ninth Edition
* Copyright John Wiley & Sons - 2013
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#define BUFFER_SIZE 25
#define READ_END 0
#define WRITE_END 1
int main(void)
{
char write_msg[BUFFER_SIZE] = "Mary says Hi here";
char read_msg[BUFFER_SIZE];
pid_t pid;
int fd[2];
/* create the pipe */
if (pipe(fd) == -1) {
fprintf(stderr,"Pipe failed");
return 1;
}
/* now fork a child process 此時,父行程產生子行程*/
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork failed");
return 1;
}
if (pid > 0) { /* parent process */
/* 都要先關掉沒用的一端 close the unused end of the pipe */
close(fd[READ_END]);
/* write to the pipe */
write(fd[WRITE_END], write_msg, strlen(write_msg)+1);
/* close the write end of the pipe */
close(fd[WRITE_END]);
}
else { /* child process */
/* 都要先關掉沒用的一端 close the unused end of the pipe */
close(fd[WRITE_END]);
/* read from the pipe */
read(fd[READ_END], read_msg, BUFFER_SIZE);
printf("child read %s\n",read_msg);
/* close the write end of the pipe */
close(fd[READ_END]);
}
return 0;
}
Terminal
編譯並執行
gcc -o unix_pipe unix_pipe.c
./unix_pipe
結果
由於父行程 fork 產生子行程,所以父行程會先寫入,子行程才有東西讀。
ps.程式執行完不會自己結束,還要我 ctrl+c 結束程式,有點怪><
參考:
greggagne/OSC9e/ch3/unix_pipe.c