2016-11-14 39 views
0

我试图编写一个程序C创建2个子进程,其中每个进程执行execvp管道问题:第一个孩子写入太多

我的问题是,第一个孩子写太多的输入到另一个孩子读的管道。

int main(int argc, char* argv[]){ 

//unnamed pipe 
int pipeFd[2], statusFirst,statusSecond; 
pid_t childPidOne,childPidTwo; 

if(pipe(pipeFd) < 0){ 
    perror("Pipe error:\n"); 
    exit(EXIT_FAILURE); 
} 

switch(childPidOne = fork()){ 
    case -1: 
     perror("First Fork error:\n"); 
     exit(EXIT_FAILURE); 
    case 0: 
     printf("First child\n"); 
     close(pipeFd[1]); 
     if((execvp(argv[1], &argv[1])) < 0){ 
      perror("First execvp error:\n"); 
     } 
     printf("End First cild\n"); 
     exit(0); 
    default: 
     //Do nothing 
     break; 
} 

switch(childPidTwo = fork()){ 
    case -1: 
     perror("Second Fork error:\n"); 
     exit(EXIT_FAILURE); 
    case 0: 
     printf("Second cild\n"); 
     close(pipeFd[0]); 
     if((execvp(argv[3], &argv[3])) < 0){ 
      perror("Second execvp error:\n"); 
     } 
     printf("End Second cild\n"); 
     exit(0); 
    default: 
     //Do nothing 
     break; 
} 


close(pipeFd[0]); 
close(pipeFd[1]); 


if((waitpid(childPidOne,&statusFirst,WUNTRACED | WCONTINUED)) < 0){ 
    perror("First waitpid error:\n"); 
}else{ 
    if (WIFEXITED(statusFirst)) { 
     printf("First exited, status=%d\n", WEXITSTATUS(statusFirst)); 
    } else if (WIFSIGNALED(statusFirst)) { 
     printf("First killed by signal %d\n", WTERMSIG(statusFirst)); 
    } else if (WIFSTOPPED(statusFirst)) { 
     printf("First stopped by signal %d\n", WSTOPSIG(statusFirst)); 
    } else if (WIFCONTINUED(statusFirst)) { 
     printf("First continued\n"); 
    } 
} 


if((waitpid(childPidTwo,&statusSecond,WUNTRACED | WCONTINUED)) < 0){ 
    perror("Second waitpid error:\n"); 
} 
if (WIFEXITED(statusSecond)) { 
    printf("Second exited, status=%d\n", WEXITSTATUS(statusSecond)); 
    } else if (WIFSIGNALED(statusSecond)) { 
    printf("Second killed by signal %d\n", WTERMSIG(statusSecond)); 
    } else if (WIFSTOPPED(statusSecond)) { 
    printf("Second stopped by signal %d\n", WSTOPSIG(statusSecond)); 
    } else if (WIFCONTINUED(statusSecond)) { 
     printf("Second continued\n"); 
     } 

    exit(0); 
return 0; 
    } 

也许我有管+叉+ execvp是如何工作的,所以让我告诉你,我在我的代码正在做一个错误的认识:

  1. 我创建一个未命名的管道 - 无论是孩子的使用相同的管道
  2. 我会通过派生他们
  3. 创建两个孩子的因为我执行我的计划是这样的:./pipeline [FIRST SYSTEM CALL] | [SECOND SYSTEM CALL]或只给你一个例子:./pipeline echo Hello | wc -m我关闭了管道的阅读网站
  4. 然后调用execvp(argv[1], &argv[1])

而这正是错误发生(我猜): 我从来没有关闭写入一侧,直到第二个孩子呢,因为如果成功execvp将一去不复返。

而且我知道execvp不会关闭打开的文件描述符(它可以通过使用fcntl中的标志来关闭,如What does the FD_CLOEXEC flag do?中所述)。

示例

让我举一个例子。

echo Hello | wc -m 

输出该结果

由于系统调用wc(字数)计数在给定的String

这是正确的字符(-m),因为你好= 5 + 1(这是\n\0我猜)这使得6。现在

,运行我的程序给出结果

或了解更多信息

echo hello | wc 

输出

1(行)1(字)6(字符)

而且./pipeline echo hello | wc

输出

3(行)9(字)56(字符)

我搜索了好几天,但我想不出它出。

任何想法?

非常感谢!

+1

如果您使用'./pipeline echo hello | wc'来运行你的程序,那么它不会做你认为的那样。你的程序看到'argv [1] == echo','[2] == hello'和_nothing else_。然后将程序的(组合)输出传送到'wc'中。为了(完全)实现我认为你想要做的事情,你需要转义管道字符并在你的代码中检测它(所以你知道命令行的哪些部分要传递给每个子进程)。 – TripeHound

+0

@TripeHound,我通过输入./pipeline echo hello \ |手动逃过角色。 wc和它适用于我,除了第二个孩子在交互模式下启动wc(等待输入并按ctrl + d标记输入结束)。这给了我1 1 6的正确结果。这意味着第一个孩子的输入被忽略。有任何想法吗 ? –

回答

0

自己解决了。

忘记使用dup2

只需在close命令后键入dup2命令,你就会没事的。