了解管道、分叉和执行 - C 编程



我试图理解 C 语言中的pipeforkexec,所以我尝试编写一个小程序,该程序接受输入字符串并在 2 个同时运行的子进程的帮助下将其打印出来。

由于代码太长,我将其发布在此链接中:https://pastebin.com/mNcRWkDg 我将用作参考。我还在底部发布了我的代码的简短版本

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

> ./echo
abcd
result -> 
abcd

我正在getline()输入并检查input_lengh是否均匀或可以分成偶数部分。如果它只是一个char它只是打印出来。

例如,如果是abcd即有 4input_length,它会将其分成 2 部分first_partab并在struct parts的帮助下second_partcd,如下所示:

struct parts p1; 
split(input, &p1);

然后我为第一个孩子设置pipefork它,然后为第二个孩子设置相同的。我将第一个子output重定向为父进程的输入,第二个子进程也是如此。让我们假设该部分按预期工作。

然后我把它写到他们的子进程输入:

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,即如何确保子进程以正确的顺序运行?由于我只是打印,如何在进程之间保存abcd并将它们连接到父进程中以将它们输出到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%sn", 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,因此您关心它们的运行顺序。通常,您不应该关心它们产生的顺序,因为它们可以按任何顺序贡献自己在最终结果中的部分。如果只有原始父进程显示结果,则代码就可以了。

最新更新