2017-10-18 117 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