pipe用法與範例
pipe是linux的system call
是用來做linux IPC(Inter-Process Communication)中一個叫做管道(pipe)的函數
[pipe規格與格式]
[pipe範例]
三個範例
1. 一個pipe兩個process單向傳輸
2. 兩個pipe兩個process雙向傳輸
3. 兩個pipe重複利用於無窮個process
以下一一展示
1. 一個pipe兩個process單向傳輸
2. 兩個pipe兩個process雙向傳輸
這個範例把一個字串用一個pipe傳過去再用另一個pipe傳回來
好了,今天的筆記到此結束
希望有幫助未來遺忘這些的自己,以及需要的人
是用來做linux IPC(Inter-Process Communication)中一個叫做管道(pipe)的函數
[pipe規格與格式]
語法:
int pipe(int pipefd[2]);
標頭檔:
#include <unistd.h>
#include <unistd.h>
回傳值:
0:pipe建立成功
-1:pipe建立失敗
-1:pipe建立失敗
注意事項:
1. 當所有正在運行的process中,此pipe的read end都關閉了,則此pipe關閉
2. 若寫入一個read end已經關閉的pipe,則調用此write()的process會得到
一個SIGPIPE,會終止程式。若忽略此signal繼續寫入會得到error叫做EPIPE
3. 若讀取一個write end已經關閉的pipe,則會得到EOF
2. 若寫入一個read end已經關閉的pipe,則調用此write()的process會得到
一個SIGPIPE,會終止程式。若忽略此signal繼續寫入會得到error叫做EPIPE
3. 若讀取一個write end已經關閉的pipe,則會得到EOF
4. pipe的write end傳完畢後,會傳送EOF給read end
我實驗的結果是,只有含有write end的process終止時才會傳送EOF
並不是傳完一串字串後就會傳送EOF
5. 若pipe的read end接收到EOF,就會關閉此read end
6. 所有沒有用到的read end、write end一定要關掉,不然process會無法終止
而當沒用到的end都關掉之後,此pipe的關閉時機就靠上述4.和5.兩點決定
我實驗的結果是,只有含有write end的process終止時才會傳送EOF
並不是傳完一串字串後就會傳送EOF
5. 若pipe的read end接收到EOF,就會關閉此read end
6. 所有沒有用到的read end、write end一定要關掉,不然process會無法終止
而當沒用到的end都關掉之後,此pipe的關閉時機就靠上述4.和5.兩點決定
[pipe範例]
三個範例
1. 一個pipe兩個process單向傳輸
2. 兩個pipe兩個process雙向傳輸
3. 兩個pipe重複利用於無窮個process
以下一一展示
1. 一個pipe兩個process單向傳輸
//pipe_simple.cpp #include <iostream> #include <unistd.h> #include <signal.h> #include <stdlib.h> int main(){ int p1[2]; if(pipe(p1)<0) std::cout << "pipe1 create error" << std::endl; signal(SIGCHLD,SIG_IGN); if(fork() == 0){ /*child process*/ std::cout << "this is child process" << std::endl; close(p1[1]); dup2(p1[0], STDIN_FILENO); /*p1 will close after STDIN receive EOF*/ close(p1[0]); execlp("cat","cat",NULL); exit(0); }else{ /*parent process*/ std::cout << "this is parent process" << std::endl; close(p1[0]); dup2(p1[1], STDOUT_FILENO); close(p1[1]); std::cout << "can u hear me?" << std::flush; } }
result :
會有這樣的結果是parent process先跑完,child process才跑完
2. 兩個pipe兩個process雙向傳輸
這個範例把一個字串用一個pipe傳過去再用另一個pipe傳回來
//pipe_simple.cpp #include <iostream> #include <unistd.h> #include <cstring> #include <signal.h> #include <stdlib.h> int main(){ int p1[2]; int p2[2]; int num = 0; int stdout_copy = dup(STDOUT_FILENO); char pipe_buff[10000] = {0}; if(pipe(p1)<0) std::cout << "pipe1 create error" << std::endl; if(pipe(p2)<0) std::cout << "pipe2 create error" << std::endl; signal(SIGCHLD,SIG_IGN); if(fork() == 0){ /*child process*/ std::cout << "this is child process" << std::endl; close(p1[1]); dup2(p1[0], STDIN_FILENO); /*p1 will close after STDIN receive EOF*/ close(p1[0]); close(p2[0]); dup2(p2[1], STDOUT_FILENO); close(p2[1]); execlp("cat","cat",NULL); exit(0); }else{ /*parent process*/ std::cout << "this is parent process" << std::endl; close(p1[0]); dup2(p1[1], STDOUT_FILENO); close(p1[1]); std::cout << "can u hear me?" << std::flush; close(p2[1]); dup2(stdout_copy,STDOUT_FILENO); /*p1 write end isn't used anymore, send EOF*/ memset(pipe_buff, 0, sizeof(pipe_buff)); num = read(p2[0],pipe_buff,sizeof(pipe_buff)); std::cout << "num: " << num << std::endl << "pipe_buff: " << pipe_buff << std::endl; close(p2[0]); /*p2 close here*/ } }
3. 兩個pipe重複利用於無窮個process
//pipe_test.cpp #include <unistd.h> #include <iostream> #include <string> #include <cstring> #include <sstream> #include <signal.h> #include <vector> #include <algorithm> #include <sys/wait.h> #define MAX_WORDS_IN_LINE 1000 #define BUFF_SIZE 100000 int main(){ int p1[2]; int p2[2]; int num = 0; int this_vbar = 0; int last_vbar = 0; int stdin_copy = dup(STDIN_FILENO); int stdout_copy = dup(STDOUT_FILENO); char pipe_buff[BUFF_SIZE] = {0}; std::string str_in = ""; std::string str_temp = ""; std::vector<std::string> cmd; std::vector<int> vbar_pos; std::stringstream ss; /*get input from std::cin, and store it*/ std::getline(std::cin,str_in,'\n'); ss.str(str_in); vbar_pos.push_back(-1); for(int i=0; ss>>str_temp; i++){ cmd.push_back(str_temp); /*store splited strings in vector cmd*/ if(cmd.at(i) == "|"){ vbar_pos.push_back(i); /*store the pos of "|" in vector vbar_pos*/ } } /*start doing the pipe task*/ for(int i=0; i<cmd.size(); i++){ if(cmd.at(i) == "|" || i==cmd.size()-1){ if(cmd.at(i) == "|"){ this_vbar = std::find(vbar_pos.begin(), vbar_pos.end(), i) - vbar_pos.begin(); last_vbar = this_vbar-1; /*this_vbar, last_vbar are indexes in vbar_pos*/ } if(pipe(p1)<0) std::cout << "create pipe1 error" << std::endl; if(pipe(p2)<0) std::cout << "create pipe2 error" << std::endl; signal(SIGCHLD,SIG_IGN); if(fork()==0){ /*child process: call execvp if cmd.at(i) is "|" or is the last word*/ if(i==cmd.size()-1){ close(p1[1]); dup2(p1[0],STDIN_FILENO); /*p1 will close after STDIN receive EOF*/ close(p1[0]); close(p2[0]); close(p2[1]); dup2(stdout_copy,STDOUT_FILENO); char* arg[MAX_WORDS_IN_LINE] = {0}; for(int j=0 ; j<(i-vbar_pos.at(this_vbar)); j++){ arg[j] = strdup(cmd.at(vbar_pos.at(this_vbar)+j+1).c_str()); } arg[i-vbar_pos.at(this_vbar)] = NULL; execvp(arg[0],arg); exit(0); }else{ close(p1[1]); dup2(p1[0],STDIN_FILENO); /*p1 will close after STDIN receive EOF*/ close(p1[0]); close(p2[0]); dup2(p2[1],STDOUT_FILENO); close(p2[1]); char* arg[MAX_WORDS_IN_LINE] = {0}; for(int j=0 ; j<(i-vbar_pos.at(last_vbar)-1); j++){ arg[j] = strdup(cmd.at(vbar_pos.at(last_vbar)+j+1).c_str()); } arg[i-vbar_pos.at(last_vbar)-1] = NULL; execvp(arg[0],arg); exit(0); } }else{ /*parent process: pass old data to the new child and store new data*/ close(p1[0]); dup2(p1[1],STDOUT_FILENO); close(p1[1]); std::cout << pipe_buff << std::flush; dup2(stdout_copy,STDOUT_FILENO); /*p1 write end isn't used anymore, send EOF*/ close(p2[1]); if(i<cmd.size()-1){ memset(pipe_buff, 0, sizeof(pipe_buff)); read(p2[0],pipe_buff, sizeof(pipe_buff)); } close(p2[0]); /*p2 close here*/ } } } }
希望有幫助未來遺忘這些的自己,以及需要的人
留言
張貼留言