我试图理解 C 语言中的 pipe
、fork
和 exec
,所以我尝试编写一个接受输入字符串的小程序并在两个同时运行的子进程的帮助下打印出来。
由于代码太长,我将其发布在这个链接中:https://pastebin.com/mNcRWkDg我将用它作为引用。我还在底部发布了我的代码的简短版本
示例应该如何处理输入abcd
:
> ./echo
abcd
result ->
abcd
我正在通过 getline()
获取输入,并检查 input_lengh
是否为偶数或可以分成偶数部分。如果它只是一个char
,它只会将其打印出来。
如果是例如abcd
,即input_length
为4,它将把它分成两部分first_part
ab
和 second_part
cd
在 struct parts
的帮助下,如下所示:
struct parts p1;
split(input, &p1);
然后我为第一个 child 设置pipe
并fork
它,然后为第二个 child 设置相同的。我将第一个子输出
重定向为父进程的输入,第二个子进程也是如此。让我们假设该部分按其应有的方式工作。
然后我将其写入其子进程输入:
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
一切都按预期进行,所以我想如果我必须像 abcd
输入那样多次调用子进程,那么事情就会变得困惑。为什么?
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
,因此您关心它们的运行顺序。通常您不应该关心它们产生的顺序,因为它们可以按任何顺序贡献最终结果的一部分。如果只有原始父进程显示结果,您的代码就可以了。
关于c - 了解管道、fork 和 exec - C 编程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59431930/