2013-10-14 80 views
1

我不會說謊。這是一個家庭作業問題。然而,就我而言,寶貝已經沒有了。現在,我只是在尋找答案,因爲我想 - 我可能會瘋了。玩具外殼沒有正確配管

該程序的目標是以類似於shell的方式執行命令ps -A | grep (inputstring) | wc -l。所以,我產生了這些流程,讓他們彼此等待。最新的過程,曾孫,execlp("ps","ps","-A",NULL),它取代了ps -A過程。在execlp之前,我確定它的標準輸出正在輸出管道。下一個進程是wait() ing,並且已經自己設置,以便輸入管道進入標準輸入,並且標準輸出進入輸出管道,並且它將執行grep等等。

我幾乎是積極的我把它設置正確。然而...程序確實如此。不。工作。

#include <stdlib.h> 
#include <iostream> 
#include <string> 

#define MAXLINE 1500 
#define READ 0 
#define WRITE 1 

using namespace std; 

int main(int argc, char** argv) { 
//* start of input block 
if (argc != 2) { 
    cout << "Usage: ./a.out arg1" << endl; 
    return 0; 
} 
string in = argv[1]; 
// end of input block */ 
int pipeA[2], pipeB[2], pid, stat; 

// get our first set of pipes 
if (pipe(pipeA) < 0) { 
    cerr << "Pipe error.\n"; 
    exit(-1); 
} 
if (pipe(pipeB) < 0) { 
    cerr << "Pipe error.\n"; 
    exit(-1); 
} 

// make the first fork 
if ((pid = fork()) < 0) { cerr << "Fork error.\n"; exit(-1); } 

if (pid > 0) { // parent case 
    wait(&stat); 
} else {   // child case 
    if ((pid = fork()) < 0) { cerr << "Fork Error\n"; exit(-1); } 
    if (pid > 0) { // child 
     wait(&stat); 
     dup2(pipeA[READ],READ); 
     execlp("wc","wc","-l",NULL); 
    } else { // grand-child 
     if ((pid = fork()) < 0) { cerr << "Fork Error\n"; exit(-1); } 
     if (pid > 0) { // still grand-child 
      wait(&stat); 
      dup2(pipeB[READ],READ); 
      dup2(pipeA[WRITE],WRITE); 
      close(pipeB[READ]); 
      execlp("grep","grep",in.c_str(),NULL); 
     } else { // great grand-child 
      dup2(pipeB[WRITE],WRITE); // t now goes to pipeB[1] 
      close(READ); 
      close(pipeB[READ]); 
      execlp("ps", "ps", "-A", NULL); 
     } 
    } 
} 
return 0; 
} 

編輯:更改爲我的代碼的雙管變體。

+0

它是如何工作的?分段故障?錯誤訊息?錯誤的輸出?沒有輸出或未經過濾的'ps'或其他東西的輸出? – sth

+2

你不應該讓你的子進程等待任何東西。 –

+1

此外,父進程應分叉兩個孩子(應該沒有孫子)。 –

回答

1

我幾乎肯定這是你要做的。提前爲草率編碼道歉。它的有些晚在這裏,我真的應該馬上睡覺:

#include <iostream> 
#include <string> 
#include <cstdlib> 
#include <cstdio> 
#include <unistd.h> 

#define READ 0 
#define WRITE 1 

// ps -A | grep argv[1] | wc -l 

int main(int argc, char** argv) 
{ 
    //* start of input block 
    if (argc != 2) 
    { 
     std::cout << "Usage: ./a.out arg1" << std::endl; 
     return 0; 
    } 

    // make local copy of argument 
    std::string in = argv[1]; 
    int fd1[2], fd2[2], pid; 

    // allocate two pipe sets 
    if (pipe(fd1) < 0 || pipe(fd2) < 0) 
    { 
     perror("Failed to create pipe."); 
     return EXIT_FAILURE; 
    } 

    // launch first child process. 
    if ((pid = fork()) < 0) 
    { 
     perror("Failed to fork child(1)"); 
     return EXIT_FAILURE; 
    } 

    if (pid == 0) 
    { 
     // wc -l process. 
     // stdin = fd2(read) 
     close(fd1[READ]); 
     close(fd1[WRITE]); 
     close(fd2[WRITE]); 
     dup2(fd2[READ],STDIN_FILENO); 
     execlp("wc","wc","-l",NULL); 
    } 

    // fork again. this time for grep 
    if ((pid = fork()) < 0) 
    { 
     perror("Failed to fork child(2)"); 
     return EXIT_FAILURE; 
    } 

    if (pid == 0) 
    { 
     // grep argv[1] process. 
     // stdin = fd1(read) 
     // stdout = fd2(write)    
     close(fd1[WRITE]); 
     close(fd2[READ]); 
     dup2(fd2[WRITE], STDOUT_FILENO); 
     dup2(fd1[READ], STDIN_FILENO); 
     execlp("grep", "grep", in.c_str(), NULL); 
    } 

    // fork once more. this time for ps -A 
    if ((pid = fork()) < 0) 
    { 
     perror("Failed to fork child(3)"); 
     return EXIT_FAILURE; 
    } 

    if (pid == 0) 
    { 
     // ps -A process. 
     // stdout = fd1(write) 
     close(fd2[WRITE]); 
     close(fd2[READ]); 
     close(fd1[READ]); 
     dup2(fd1[WRITE], STDOUT_FILENO); 
     execlp("ps", "ps", "-A", NULL); 
    } 

    int stat=0; 
    wait(&stat); 

    return EXIT_SUCCESS; 
} 

在我的系統,ps -A報告141線,這些41有字System某處內,只需運行ps -A | grep System | wc -l驗證。上面的代碼生成的輸出完全相同。

希望它可以幫助你。

+0

你的代碼也在我的系統上工作!我比較你的和我自己的兩管變體,看看我能不能找出主要區別是什麼,爲什麼你的工作原理,但我的原理不是。看起來可能是wait()語句,嵌套,或者我沒有關閉沒有使用的管道。無論哪種方式,非常感激;我應該能夠在一個小時內弄清楚,最後我的大腦可以讓我睡覺。 – Gearov

+0

這不需要多於一層的嵌套(僅限於父母子女)。我試圖確保代碼中的註釋反映爲什麼每個管道都被使用,並且通過推論,爲什麼其他叉爲什麼不需要,因此應該關閉。雖然在技術上有功能,但這真的應該等到'wc'進程pid完成了,但是我把它留給你。 – WhozCraig

0

我不確定,但也許在等待孩子之前調用dup2可以解決管道問題。

我不確定的原因是它通常將stdin和stdout緩衝區化,所以我認爲即使你在孩子完成運行後將它們連接起來,你也應該得到相同的結果,但也許(如果有人知道這個問題的答案,請糾正我)stdin和stdout的緩衝區會在子進程結束時被擦除。

另外,你可以更新你的問題中的代碼,以包含修改後的代碼與兩組管道?

+0

已更新爲雙管系統。我將在下一次迭代中嘗試您的建議。 – Gearov