理解pipe、fork和exec-C编程
我试图理解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,
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。这不是正确的顺序。我编辑了我的问题并更正了您指出的错误,但是这个答案并没有回答我的问题。我已经更新了答案来回答你的主要问题。谢谢你试图帮助我,但这并没有改变我的输出。我将等待,看看是否有人可以帮助我得到它作为一个完整的输出在正确的顺序。无论如何,我感谢你的帮助。当我做出这些改变时,这个程序实际上正在等待我。问题是,第二个子代继承了用于与第一个子代通信的管道,这会阻止第一个子代在父代关闭时获得EOFpipeEndsSecondChild2[1]
我编辑了我的问题并更正了您指出的错误,但是这个答案并没有回答我的问题。我已经更新了答案来回答你的主要问题。谢谢你试图帮助我,但这并没有改变我的输出。我将等待,看看是否有人可以帮助我得到它作为一个完整的输出在正确的顺序。无论如何,我感谢你的帮助。当我做出这些改变时,这个程序实际上正在等待我。问题是,第二个子级继承了用于与第一个子级通信的管道,这会阻止第一个子级在父级关闭pipeEn时获得EOF