【问题标题】:Creating multiple child processes with a single pipe使用单个管道创建多个子进程
【发布时间】:2013-05-20 04:15:10
【问题描述】:

我需要创建三个子进程,每个子进程都从命令行参数中读取一个字符串并将该字符串写入一个管道。然后父级将从管道中读取字符串并将它们全部显示在屏幕上。我尝试对两个进程进行测试,它打印一个字符串两次,而不是两个。

#include <stdio.h>
#include <unistd.h>

int main (int argc, char *argv[]) {

    char *character1 = argv[1];
    char *character2 = argv[2]; 

    char inbuf[100]; //creating an array with a max size of 100

    int p[2]; // Pipe descriptor array
    pid_t pid1; // defining pid1 of type pid_t
    pid_t pid2; // defining pid2 of type pid_t

    if (pipe(p) == -1) {
        fprintf(stderr, "Pipe Failed"); // pipe fail
    }

    pid1 = fork(); // fork

    if (pid1 < 0) {
        fprintf(stderr, "Fork Failed"); // fork fail
    }

    else if (pid1 == 0){ // if child process 1
        close(p[0]); // close the read end
        write(p[1], character1, sizeof(&inbuf[0])); // write character 1 to the pipe
    }

    else { // if parent, create a second child process, child process 2
        pid2 = fork();  

        if (pid2 < 0) {
        fprintf(stderr, "Fork Failed"); // fork fail
        }

        if (pid2 = 0) { // if child process 2
            close(p[0]); // close the read end
            write(p[1], character2, sizeof(&inbuf[0])); // write character 2 to the pipe
        }

        else { // if parent process
            close(p[1]); // close the write end

            read(p[0], inbuf, sizeof(&inbuf[0])); // Read the pipe that both children write to 
            printf("%s\n", inbuf); // print 

            read(p[0], inbuf, sizeof(&inbuf[0])); // Read the pipe that both children write to 
            printf("%s\n", inbuf); // print 
        }
    } 
}

【问题讨论】:

    标签: unix process pipe


    【解决方案1】:

    在没有更多数据可供读取之前,您的代码不会一直循环。它只进行一次读取。它也不检查read() 返回的值,但应该检查。

    我已将fork()write()(和错误检查)代码抽象为一个函数。这似乎有效:

    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    static void child(int fd, const char *string)
    {
        pid_t pid = fork();
        int len = strlen(string);
        if (pid < 0)
        {
            fprintf(stderr, "%.5d: failed to fork (%d: %s)\n",
                    (int)getpid(), errno, strerror(errno));
            exit(1);
        }
        else if (pid > 0)
            return;
        else if (write(fd, string, len) != len)
        {
            fprintf(stderr, "%.5d: failed to write on pipe %d (%d: %s)\n",
                    (int)getpid(), fd, errno, strerror(errno));
            exit(1);
        }
        else
            exit(0);
    }
    
    int main (int argc, char *argv[])
    {
        char inbuf[100]; //creating an array with a max size of 100
        int p[2]; // Pipe descriptor array
    
        if (argc != 4)
        {
            fprintf(stderr, "Usage: %s str1 str2 str3\n", argv[0]);
            return 1;
        }
    
        if (pipe(p) == -1)
        {
            fprintf(stderr, "Pipe Failed"); // pipe fail
            return 1;
        }
    
        for (int i = 0; i < 3; i++)
            child(p[1], argv[i+1]);
    
        int nbytes;
        close(p[1]); // close the write end
        while ((nbytes = read(p[0], inbuf, sizeof(inbuf))) > 0)
            printf("%.*s\n", nbytes, inbuf); // print 
    
        return 0;
    }
    

    我多次运行该命令,每次都使用命令行:

    ./p3 'message 1' 'the second message' 'a third message for the third process'
    

    在一次运行中,输出为:

    the second messagemessage 1
    a third message for the third process
    

    另一方面,我得到了:

    the second messagemessage 1a third message for the third process
    

    另一方面,我得到了:

    message 1
    the second messagea third message for the third process
    

    (这是在配备 Intel Core i7、运行 Mac OS X 10.8.3 并使用 GCC 4.7.1 的 MacBook Pro 上。)

    【讨论】:

    • 我忘了说。我尝试使用两次 read 语句并打印两次。它打印第一个字符串两次,而不是两个字符串。
    • 对其进行了编辑以包含该内容。
    • 由于您没有注意来自read() 的返回值,所以没人能猜到您返回的是什么。即使忽略写入错误,也必须注意read() 返回的内容;除非您查看返回的字节数,否则您不知道有多少数据是有效的。
    • 请注意,您的行 read(p[0], inbuf, sizeof(&amp;inbuf[0])); 是可疑的,因为它读取一个字符指针的大小(这就是 sizeof(&amp;inbuf[0]) 的计算结果),可能是 4 个字节或 8 个字节。您应该使用sizeof(inbuf),并且应该捕获读取的字节数,以便只打印那么多字节。
    • 另外,通常情况下,我会在关闭子进程中未使用的管道端时打扰您。在这种情况下,这并不重要,因为子进程会执行简单的写入然后退出,这会关闭管道的两端。
    猜你喜欢
    • 1970-01-01
    • 2015-05-04
    • 1970-01-01
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-27
    相关资源
    最近更新 更多