2017-10-18 179 views
1

我正在寫一個簡單的管道程序會要求兩個命令,然後運行程序,就好像他們進入bash作爲cmd1 | cmd2。然後它應該循環並再次詢問,直到其中一個命令是quit等待(NULL)似乎會導致孩子停止執行

我已經寫了這麼多:

#include<iostream> 
#include<string> 
#include<sys/types.h> 
#include<sys/wait.h> 
#include<string.h> 
#include<unistd.h> 
#include<stdlib.h> 
#include<stdio.h> 
#include<signal.h> 

using namespace std; 

int main(int argc, char *argv[]) 
{ 
    int pid1, pid2, errchk; 
    int pip[2]; 
    char cmd1[128]; 
    char cmd2[128]; 
    int i = 0; 
    int status; 

    errchk = pipe(pip);//make pipe 
    if(errchk == -1)//check for error in pipe 
    { 
     perror("pipe"); 
     exit(1); 
    } 

    while(i<3) 
    { 
     i++; 
     //Enter commands here 
     cout<<"Enter cmd1: "; 
     cin>>cmd1; 
     cout<<"Enter cmd2: "; 
     cin>>cmd2; 
     //if a command is quit... quit 
     if(strcmp(cmd1,"quit")==0 || strcmp(cmd2,"quit") == 0) 
     { 
      cout<<"Quitting...\n"; 
      exit(1); 
     } 

     pid1 = fork(); 
     cout<<"first fork makes pids: "<<pid1<<endl; 
     if(pid1 < 0) 
     { 
      perror("fork"); 
      exit(1); 
     } 

     else if(pid1 == 0) //MAIN CHILD 
     { 
      cout<<"In main child with pid: "<<pid1<<endl; 
      pid2 = fork(); 
      cout<<"second fork makes pids: "<<pid2<<endl; 
      if(pid2 == 0)//SUB CHILD 2 to run cmd2 
      { 
       cout<<"In child of second fork"<<endl; 
       close(0); 
       close(pip[1]); 
       dup(pip[0]); 
       execvp(cmd2,argv);//execute command2 and die 
      } 
      else if(pid2 > 0)//SUB CHILD 1 to run cmd1 
      { 
       cout<<"In parent of second fork"<<endl; 
       close(1); 
       close(pip[0]); 
       dup(pip[1]); 
       execvp(cmd1,argv);//execute command1 and die 
      } 
     } 
     else if(pid1 > 0) //MAIN PARENT 
     { 
      wait(NULL);//wait for cmd1 
      wait(NULL);//wait for cmd2 
      cout<<"DONE executing"<<endl; //keep going 
     } 
    } 
    return 0; 
} 

當我運行它,並進入lswc 我得到的輸出是:

Enter cmd1: ls 
Enter cmd2: wc 
first fork makes pids: 5785 
first fork makes pids: 0 
In main child with pid: 0 
second fork makes pids: 5786 
In parent of second fork 
second fork makes pids: 0 
In child of second fork 
DONE executing 
     5  5  54 

我的主要問題是,我應後ls|wc而不是其他的方式都Done executing來。 我想了wait(NULL)不工作,但我不知道。

請指教。 並謝謝。

+1

你不能等待孫子。 child1必須等待的child2 –

+0

該行'CIN >> CMD1;'和'CIN >> CMD2;'可以溢出陣列如果惡意用戶類型足夠長的字符串,不空格,導致未定義行爲。這是C++,所以請使用'std :: string',而不是'char [128]'。 – aschepler

+0

我必須使用char,因爲execvp不能使用字符串。 – sshulgan

回答

1

您有:

parent 
    1. child1 
    2. child2 
    2. exec() 
    1. exec() 

當您在child1 Exec時,得到的child2到重設父初始化,您可以不再等待的child2終止。

所以我們需要做重構的一點點得到的東西看起來像:

parent 
    1. child1 
    1. exec() 
    2. child2 
    2. exec() 
wait() x 2 

在你自己的代碼立足這一點,與重構來完成類似的外觀類似的代碼(一些評論在直插式):

#include<iostream> 
#include<string> 
#include<sys/types.h> 
#include<sys/wait.h> 
#include<string.h> 
#include<unistd.h> 
#include<stdlib.h> 
#include<stdio.h> 
#include<signal.h> 

using namespace std; 

int main(int argc, char *argv[]) 
{ 
    int pid1, pid2, errchk; 
    int pip[2]; 
    char cmd1[128]; 
    char cmd2[128]; 
    int status; 

    while(true) 
    { 
     errchk = pipe(pip);//make pipe 
     if(errchk == -1)//check for error in pipe 
     { 
      perror("pipe"); 
      exit(1); 
     } 

     //Enter commands here 
     cout<<"Enter cmd1: "; 
     cin>>cmd1; 
     cout<<"Enter cmd2: "; 
     cin>>cmd2; 
     //if a command is quit... quit 
     if(strcmp(cmd1,"quit")==0 || strcmp(cmd2,"quit") == 0) 
     { 
      cout<<"Quitting...\n"; 
      exit(1); 
     } 

     pid1 = fork(); 
     cout<<"first fork makes pids: "<<pid1<<endl; 
     if(pid1 < 0) 
     { 
      perror("fork"); 
      exit(1); 
     } 
     if (pid1 == 0) // in child 
     { 
      cout<<"In child of first fork"<<endl; 
      close(pip[0]); // close read-end of pipe 
      close(0); // close stdin 
      close(1); // close stdout 
      dup2(pip[1], 1); // write-end of pipe is stdout of cmd1 
      argv[0] = cmd1; // make it look like the command in the ps output 
      execvp(cmd1,argv);//execute command1 and die 
      fprintf(stderr, "execvp(1): `%s': %s\n", cmd1, strerror(errno)); 
      return 0; 
     } 
     pid2 = fork(); 
     cout<<"second fork makes pids: "<<pid2<<endl; 
     if (pid2 < 0) 
     { 
      perror("fork2"); 
      exit(1); 
     } 
     if (pid2 == 0) 
     { 
      cout<<"In child of second fork"<<endl; 
      close(pip[1]); // close write-end of pipe 
      close(0); // close stdin 
      dup2(pip[0], 0); // read-end of pipe is stdin of cmd2 
      argv[0] = cmd2; // update ps output 
      execvp(cmd2,argv);//execute command2 and die 
      fprintf(stderr, "execvp(1): `%s': %s\n", cmd2, strerror(errno)); 
      return 0; 
     } 
     if(pid1 > 0) //MAIN PARENT 
     { 
      // close remaining pipe handles in parent 
      close(pip[0]); 
      close(pip[1]); 
      wait(0);//wait for one command to run 
      wait(0);//wait for a second command to run 
      cout<<"DONE executing"<<endl; //keep going 
     } 
    } 
    return 0; 
} 
+0

是啊,我意識到你現在在做什麼 - 我在原來的答覆作出了錯誤。我需要編輯答案 – Petesh

+0

我將管道上方的while循環移動並使其條件成爲'true',以便它可以連續詢問2個命令,執行然後再請求2個等...但是在第一次運行通過放入'ls'和'wc'顯示'0 0 0',然後在第二次開始提供正確的數據?任何想法爲什麼? – sshulgan

+0

是的,它會只製作的第一次圓,所以移動while循環管道被修復到我的變化。我不知道爲什麼你第一次得到'0 0 0' - 如果execvp失敗,你可能會看到,所以我已經提前並在兩個execvps之後進行了額外的錯誤檢查以顯示錯誤消息在這種情況下。 – Petesh