理解pipe、fork和exec-C编程

理解pipe、fork和exec-C编程,c,pipe,fork,exec,C,Pipe,Fork,Exec,我试图理解C语言中的pipe、fork和exec,因此我试图编写一个小程序,在同时运行的两个子进程的帮助下获取输入字符串并将其打印出来 由于代码太长,我将其发布在这个链接中:我将使用它作为参考。我还在底部发布了我的代码的简短版本 示例:它应该如何处理输入abcd: > ./echo abcd result -> abcd 我正在通过getline()进行输入,并检查输入长度是否为偶数,或者是否可以分成偶数部分。如果只有一个字符,它就打印出来 例如,如果它是abcd即输入长度为4,

我试图理解C语言中的
pipe
fork
exec
,因此我试图编写一个小程序,在同时运行的两个子进程的帮助下获取输入字符串并将其打印出来

由于代码太长,我将其发布在这个链接中:我将使用它作为参考。我还在底部发布了我的代码的简短版本

示例:它应该如何处理输入
abcd

> ./echo
abcd
result -> 
abcd
我正在通过
getline()
进行输入,并检查
输入长度是否为偶数,或者是否可以分成偶数部分。如果只有一个字符,它就打印出来

例如,如果它是
abcd
输入长度为4,它将在
结构部分的帮助下将其拆分为两部分
第一部分
ab
第二部分
cd
,如下所示:

struct parts p1; 
split(input, &p1);
然后我为第一个孩子和第二个孩子设置
pipe
,然后为第二个孩子设置相同的
fork
。我将第一个子进程的
输出重定向为父进程的输入,第二个子进程也是如此。让我们假设该部分工作正常

然后我将其写入其子进程输入:

write(pipeEndsFirstChild2[1], p1.first_half,  strlen(p1.first_half));
write(pipeEndsSecondChild2[1], p1.second_half,  strlen(p1.second_half));
之后,我用
fdopen()
打开它们的输出,并用
fgets()

最后,我分配内存,并通过以下方式处理两个结果:

char *result = malloc(strlen(readBufFirstChild) + strlen(readBufSecondChild));

strcat(result, readBufFirstChild);
strcat(result, readBufSecondChild);
我使用
stderr
查看输出,因为
stdout
被重定向,我得到的是:

>./echo 
abcd
result ->
cd
result ->
ab
result -> 
����
问题: 如何让子进程1首先给我
ab
,然后让第二个子进程给我
cd
,即如何确保子进程以正确的顺序运行?由于我只是在打印,如何在进程之间保存
ab
cd
,并在父进程中对它们进行压缩,以将它们输出到
stdout

如果我尝试:

 >./echo
 ab    
 result ->
 ab
一切都按预期进行,所以我想如果我必须多次调用子进程,就像在输入中那样,那么就会出现问题。为什么?

int main(int argc, char *argv[])
{
int status = 0; 
char *input;
input = getLine();
int input_length = strlen(input);

if((input_length/2)%2 == 1 && input_length > 2)
{
    usage("input must have even length");
}

if (input_length == 1)
{
    fprintf(stdout, "%s", input);
}else
{
    struct parts p1; 
    split(input, &p1);

    int pipeEndsFirstChild1[2];
    int pipeEndsFirstChild2[2];

    .
    .
    .
    pid_t pid1 = fork();
    redirectPipes(pid1, pipeEndsFirstChild1, pipeEndsFirstChild2);

    int pipeEndsSecondChild1[2];
    int pipeEndsSecondChild2[2];

    .
    .
    .
    pid_t pid2 = fork();
    redirectPipes(pid2, pipeEndsSecondChild1, pipeEndsSecondChild2);


    // write to 1st and 2nd child input
    write(pipeEndsFirstChild2[1], p1.first_half,  strlen(p1.first_half));
    write(pipeEndsSecondChild2[1], p1.second_half,  strlen(p1.second_half));

    .
    .
    .

    // open output fd of 1st child
    FILE *filePointer1 = fdopen(pipeEndsFirstChild1[0], "r");

    // put output into readBufFirstChild
    fgets(readBufFirstChild,sizeof(readBufFirstChild),filePointer1);

     // open output fd of 2nd child
    FILE *filePointer2 = fdopen(pipeEndsSecondChild1[0], "r");

    // open output fd of 2st child
    fgets(readBufSecondChild,sizeof(readBufSecondChild),filePointer2);

    //concat results
   char *result = malloc(strlen(readBufFirstChild) + 
   strlen(readBufSecondChild) + 1);
   strcpy(result, readBufFirstChild);
   strcat(result, readBufSecondChild);

    fprintf(stderr, "result ->\n%s\n", result);

    if(wait(&status) == -1){
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
 }
}

如果两个子进程都有可用的输入,则无法控制它们的运行顺序

在应用程序中解决此问题的方法是,在读取第一个子级的响应之前,不应向第二个子级写入

write(pipeEndsFirstChild2[1], p1.first_half,  strlen(p1.first_half));
char readBufFirstChild[128];
FILE *filePointer1 = fdopen(pipeEndsFirstChild1[0], "r");
fgets(readBufFirstChild,sizeof(readBufFirstChild),filePointer1);

write(pipeEndsSecondChild2[1],  p1.second_half,  strlen(p1.second_half));
char readBufSecondChild[128];
FILE *filePointer2 = fdopen(pipeEndsSecondChild1[0], "r");
fgets(readBufSecondChild,sizeof(readBufSecondChild),filePointer2);
我忽略了错误检查和关闭所有不必要的管端


您只需要这样做,因为每个进程都在将其结果部分打印到stderr,所以您关心它们的运行顺序。通常情况下,您不应该关心它们的结果顺序,因为它们可以按任何顺序贡献最终结果的一部分。如果只有原始父进程显示结果,那么您的代码就可以了。

如果子进程都有可用的输入,则无法控制它们的运行顺序

在应用程序中解决此问题的方法是,在读取第一个子级的响应之前,不应向第二个子级写入

write(pipeEndsFirstChild2[1], p1.first_half,  strlen(p1.first_half));
char readBufFirstChild[128];
FILE *filePointer1 = fdopen(pipeEndsFirstChild1[0], "r");
fgets(readBufFirstChild,sizeof(readBufFirstChild),filePointer1);

write(pipeEndsSecondChild2[1],  p1.second_half,  strlen(p1.second_half));
char readBufSecondChild[128];
FILE *filePointer2 = fdopen(pipeEndsSecondChild1[0], "r");
fgets(readBufSecondChild,sizeof(readBufSecondChild),filePointer2);
我忽略了错误检查和关闭所有不必要的管端



您只需要这样做,因为每个进程都在将其结果部分打印到stderr,所以您关心它们的运行顺序。通常情况下,您不应该关心它们的结果顺序,因为它们可以按任何顺序贡献最终结果的一部分。如果只有原始父进程显示结果,您的代码就可以了。

请从链接复制代码的相关部分。有些人不能/不想访问外部链接。@AjayBrahmakshatriya我在帖子底部添加了它。为什么需要
buf
buf2
?您可以直接从
p1.first\u half
p1.second\u half
写入。子进程将并发运行,但这并不重要。您首先读取的是第一个子项,因此您应该按正确的顺序获取结果。@Barmar正如我在上面的输出中所示,我先获取cd,然后获取ab。这不是正确的顺序。请从链接复制代码的相关部分。有些人不能/不想访问外部链接。@AjayBrahmakshatriya我在帖子底部添加了它。为什么需要
buf
buf2
?您可以直接从
p1.first\u half
p1.second\u half
写入。子进程将并发运行,但这并不重要。您首先阅读的是第一个孩子的内容,因此您应该按照正确的顺序获得结果。@Barmar正如我在上面的输出中所示,我先获得cd,然后获得ab。这不是正确的顺序。我编辑了我的问题并更正了您指出的错误,但是这个答案并没有回答我的问题。我已经更新了答案来回答你的主要问题。谢谢你试图帮助我,但这并没有改变我的输出。我将等待,看看是否有人可以帮助我得到它作为一个完整的输出在正确的顺序。无论如何,我感谢你的帮助。当我做出这些改变时,这个程序实际上正在等待我。问题是,第二个子代继承了用于与第一个子代通信的管道,这会阻止第一个子代在父代关闭时获得EOF
pipeEndsSecondChild2[1]
我编辑了我的问题并更正了您指出的错误,但是这个答案并没有回答我的问题。我已经更新了答案来回答你的主要问题。谢谢你试图帮助我,但这并没有改变我的输出。我将等待,看看是否有人可以帮助我得到它作为一个完整的输出在正确的顺序。无论如何,我感谢你的帮助。当我做出这些改变时,这个程序实际上正在等待我。问题是,第二个子级继承了用于与第一个子级通信的管道,这会阻止第一个子级在父级关闭
pipeEn时获得EOF