c - 了解管道、fork 和 exec - C 编程

标签 c pipe fork exec

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

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

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

> ./echo
abcd
result -> 
abcd

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

如果是例如abcd,即input_length为4,它将把它分成两部分first_part absecond_part cdstruct parts 的帮助下,如下所示:

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

然后我为第一个 child 设置pipefork它,然后为第二个 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,即如何确保子进程以正确的顺序运行?由于我只是打印如何在进程之间保存 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%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/

相关文章:

c - 如何让父子进程互相监听?

c - 与 "int (*p)[SIZE]"区分开来的声明 "int *p[SIZE]"的名称是什么?

c - 如何通过cronjob调度定期调用C程序中的特定函数?

c - 什么是 TpCallbackMayRunLong()?

c# - 如何解锁 ConnectNamedPipe 和 ReadFile? [C#]

c - 与 FIFO 通信的两个程序使用 for 循环但不使用 while 循环

子进程等待另一个进程完成并且 main() 没有执行到最后

c++ - fork 、管道和文件操作

c - 如何扫描这个字符串

pid - fork() 之后的 PID 是什么?