【问题标题】:Understanding pipe, fork and exec - C programming理解 pipe、fork 和 exec - C 编程
【发布时间】:2019-12-20 22:21:39
【问题描述】:

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

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

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

> ./echo
abcd
result -> 
abcd

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

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

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

然后我为第一个孩子设置pipe,为它设置fork,然后为第二个孩子设置相同的设置。我将第一个孩子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,即如何确保子进程以正确的顺序运行?由于我只打印如何在进程之间保存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);
 }
}

【问题讨论】:

  • 请从链接中复制代码的相关部分。有些人不能/不想访问外部链接。
  • @AjayBrahmakshatriya 我在帖子底部添加了它。
  • 为什么需要buf 和buf2?您可以直接从p1.first_half 和p1.second_half 写信。
  • 子进程将同时运行,但没关系。您首先从第一个孩子开始阅读,因此您应该以正确的顺序获得结果。
  • @Barmar 正如我在上面的输出中所示,我先得到 cd,然后得到 ab。这不是正确的顺序。

标签: c pipe fork exec


【解决方案1】:

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

在您的应用程序中解决此问题的方法是,在您阅读第一个孩子的回复之前,您不应该写第二个孩子。

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,因此您关心它们运行的​​顺序。通常你不应该关心它们产生的顺序,因为它们可以按任何顺序贡献最终结果的一部分。如果只有原始父进程显示结果,您的代码就可以了。

【讨论】:

  • 我编辑了我的问题并更正了你指出的错误,但是这个答案没有回答我的问题。
  • 我已更新答案以解决您的主要问题。
  • 感谢您尝试帮助我,但这不会改变我的输出。我会等着看是否有人可以帮助我以正确的顺序将它作为一个完整的输出。无论如何,我感谢您的帮助。
  • 当我进行这些更改时,程序实际上已经挂起。问题是第二个孩子继承了用于与第一个孩子通信的管道,这阻止了第一个孩子在父母关闭时获得 EOF pipeEndsSecondChild2[1]
猜你喜欢
  • 1970-01-01
  • 2011-07-02
  • 2015-01-22
  • 2014-06-09
  • 1970-01-01
  • 2013-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多