如何使用管道连接C中的两个子进程

how to use pipe to connect two child process in C

我正在自学一本OS课本并做作业:

Write a program that creates two children, and connects the standard output of one to the standard input of the other, using the pipe() system call.

然后我试着这样写我的代码:


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
    printf("parent in pid: (%d)\n", (int)getpid());
    fflush(stdout);
    int p1[2], p2[2];
    pipe(p1);
     pipe(p2);
    
    char buff1[100];
    char buff2[100];
    int rc = fork();
    if (rc < 0)
    {
        fprintf(stderr, "fork failed");
        exit(1);
    }
    else if (rc == 0)
    {
        int fd = open("test1.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
        printf("%d\n", fd);
        printf("entering child1 process at pid : (%d)\n", (int)getpid());
        dup2(p1[0], STDIN_FILENO);
        dup2(p2[1], STDOUT_FILENO);
        int n = read(STDIN_FILENO, buff1, sizeof buff1);
        
        puts("this is a message from child 1");
        write(fd, buff1, n);
    }
    else
    {
        int rc2 = fork();
        if (rc2 == 0)
        {
            int fd2 = open("test2.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
            printf("%d\n", fd2);
            printf("entering child2 process at pid : (%d)\n", (int)getpid());
            dup2(p2[0], STDIN_FILENO);
            dup2(p1[1], STDOUT_FILENO);
            int n = read(STDIN_FILENO, buff2, sizeof buff2);
            
            puts("this is a message from child 2");
            write(fd2, buff2, n);
        }
        else
        {
            printf("final parent in pid: (%d)\n", (int)getpid());
        }
        
    }
    return 0;
}

如果一切顺利。我应该在 txt 文件中看到来自 child1 或 child2 的消息。但是当我 运行 这段代码时什么也没有发生。 但是如果我像这样删除任何一个读取语句:


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
    printf("parent in pid: (%d)\n", (int)getpid());
    fflush(stdout);
    int p1[2], p2[2];
    pipe(p1);
     pipe(p2);
    
    char buff1[100];
    char buff2[100];
    int rc = fork();
    if (rc < 0)
    {
        fprintf(stderr, "fork failed");
        exit(1);
    }
    else if (rc == 0)
    {
        int fd = open("test1.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
        printf("%d\n", fd);
        printf("entering child1 process at pid : (%d)\n", (int)getpid());
        dup2(p1[0], STDIN_FILENO);
        dup2(p2[1], STDOUT_FILENO);
        //int n = read(STDIN_FILENO, buff1, sizeof buff1);
        
        puts("this is a message from child 1");
        //write(fd, buff1, n);
    }
    else
    {
        int rc2 = fork();
        if (rc2 == 0)
        {
            int fd2 = open("test2.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
            printf("%d\n", fd2);
            printf("entering child2 process at pid : (%d)\n", (int)getpid());
            dup2(p2[0], STDIN_FILENO);
            dup2(p1[1], STDOUT_FILENO);
            int n = read(STDIN_FILENO, buff2, sizeof buff2);
            
            puts("this is a message from child 2");
            write(fd2, buff2, n);
        }
        else
        {
            printf("final parent in pid: (%d)\n", (int)getpid());
        }
        
    }
    return 0;
}

或者像这样


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
    printf("parent in pid: (%d)\n", (int)getpid());
    fflush(stdout);
    int p1[2], p2[2];
    pipe(p1);
     pipe(p2);
    
    char buff1[100];
    char buff2[100];
    int rc = fork();
    if (rc < 0)
    {
        fprintf(stderr, "fork failed");
        exit(1);
    }
    else if (rc == 0)
    {
        int fd = open("test1.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
        printf("%d\n", fd);
        printf("entering child1 process at pid : (%d)\n", (int)getpid());
        dup2(p1[0], STDIN_FILENO);
        dup2(p2[1], STDOUT_FILENO);
        int n = read(STDIN_FILENO, buff1, sizeof buff1);
        
        puts("this is a message from child 1");
        write(fd, buff1, n);
    }
    else
    {
        int rc2 = fork();
        if (rc2 == 0)
        {
            int fd2 = open("test2.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
            printf("%d\n", fd2);
            printf("entering child2 process at pid : (%d)\n", (int)getpid());
            dup2(p2[0], STDIN_FILENO);
            dup2(p1[1], STDOUT_FILENO);
            //int n = read(STDIN_FILENO, buff2, sizeof buff2);
            
            puts("this is a message from child 2");
            //write(fd2, buff2, n);
        }
        else
        {
            printf("final parent in pid: (%d)\n", (int)getpid());
        }
        
    }
    return 0;
}

我可以从双方的 txt 文件中看到正确的输出。 我想知道我的代码中发生了什么,第一种情况出了什么问题?

代码中的几个问题:

  • 您的两个子进程都在从管道读取时阻塞,但没有任何内容写入其中,因此它们永远阻塞。解决方法是在读取之前写入管道。

  • 需要
  • fflush 以确保 stdout 缓冲区写入 STDOUT_FILENOstdout 在连接到终端时为 line-buffered,否则为 block-buffered(在调用 main 之前确定),因此 putsstdout 没有连接到程序 start-up 的终端。

  • 父进程应该等待子进程终止。 If/when 父进程是会话领导者并且它终止,内核将 SIGHUP 发送到其组中的所有(子)进程。 More details.

修复的代码:

int main() {
    printf("parent in pid: (%d)\n", (int)getpid());
    fflush(stdout);
    int p1[2], p2[2];
    pipe(p1);
    pipe(p2);

    char buff1[100];
    char buff2[100];
    int rc = fork();
    if (rc == 0)
    {
        int fd = open("test1.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
        printf("%d\n", fd);
        printf("entering child1 process at pid : (%d)\n", (int)getpid());
        fflush(stdout);
        dup2(p1[0], STDIN_FILENO);
        dup2(p2[1], STDOUT_FILENO);
        puts("this is a message from child 1");
        fflush(stdout);
        int n = read(STDIN_FILENO, buff1, sizeof buff1);
        write(fd, buff1, n);
    }
    else
    {
        int rc2 = fork();
        if (rc2 == 0)
        {
            int fd2 = open("test2.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
            printf("%d\n", fd2);
            printf("entering child2 process at pid : (%d)\n", (int)getpid());
            fflush(stdout);
            dup2(p2[0], STDIN_FILENO);
            dup2(p1[1], STDOUT_FILENO);
            puts("this is a message from child 2");
            fflush(stdout);
            int n = read(STDIN_FILENO, buff2, sizeof buff2);
            write(fd2, buff2, n);
        }
        else
        {
            printf("final parent in pid: (%d)\n", (int)getpid());
            waitpid(rc, &rc, 0);
            waitpid(rc2, &rc2, 0);
        }
    }
    return 0;
}