C语言 使用管道在两个子进程之间进行通信

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6877697/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 09:15:47  来源:igfitidea点击:

communicating between two child processes with pipes

cprocessforkpipe

提问by David

I'm trying to write code that spawns two child processes that send each other a message over a pipe then terminate. However, when I run the following code only child2 prints it's greeting but child 1 still prints the message it gets from child 2 where child 1 doesn't.

我正在尝试编写生成两个子进程的代码,这些子进程通过管道相互发送消息然后终止。但是,当我运行以下代码时,只有 child2 打印它的问候语,但 child 1 仍然打印它从 child 2 获得的消息,而 child 1 没有。

Does anybody know what's wrong with my methodology?

有人知道我的方法有什么问题吗?

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char** argv) {
    char chld_1_send[20] = "hello from child 1";
    char chld_1_recv[20];
    char chld_2_send[20] = "hi from child 2";
    char chld_2_recv[20];

    int chld_1_outgoing[2];
    int chld_2_outgoing[2];

    pipe(chld_1_outgoing);
    pipe(chld_2_outgoing);

    int chld_1_status, chld_2_status;
    pid_t chld_1, chld_2;

    chld_1 = fork();

    if(chld_1 == 0) {
        chld_2 = fork();
    }

    if(chld_1 == 0 && chld_2 == 0) {
        printf("parent [pid:%d] waiting on both children to finish\n", getpid());

        while(wait(&chld_1_status) != chld_1 && wait(&chld_2_status) != chld_2) {}

        printf("done waiting\n");
    }
    else if(chld_1 != 0 && chld_2 == 0) {
        printf("this is child 1 [pid:%d] with parent [pid:%d]\n", getpid(), getppid());

        write(chld_1_outgoing[1], chld_1_send, strlen(chld_1_send));
        while(read(chld_1_outgoing[0], &chld_1_recv, sizeof(chld_2_recv)) < 0) {}

        printf("child 2 said '%s'\n", chld_1_recv);
        exit(0);
    }
    else if(chld_2 != 0 && chld_1 == 0) {
        printf("this is child 2 [pid:%d] with parent [pid:%d]\n", getpid(), getppid());

        write(chld_2_outgoing[1], chld_2_send, strlen(chld_2_send));
        while(read(chld_2_outgoing[0], &chld_2_recv, sizeof(chld_2_recv)) < 0) {}

        printf("child 1 said '%s'\n", chld_2_recv);

        exit(0);
    }

    printf("both children have terminated successfully\n");

    return 0;
}

However, running this command prints out this to the terminal and goes into an infinite loop:

但是,运行此命令会将其打印到终端并进入无限循环:

$ this is child 2 [pid:15713] with parent [pid:1]
child 1 said 'hi from child 2'
parent [pid:15714] waiting on both children to finish

回答by celavek

Following is a simple example which certainly can be improved but should get you started. Also follow Link1and Link2for more info.

下面是一个简单的例子,当然可以改进,但应该让你开始。另请关注Link1Link2以获取更多信息。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

/* max  receiving buffer size; Note: no check or enforcement is made on this value*/
#define BUF_SIZE 256

int main()
{
    int pfd1[2];
    int pfd2[2];

    ssize_t numRead = -1;
    /* Note: working under the assumption that the messages
       are of equal length*/
    const char* messageOne = "Hello from child ONE.\n";
    const char* messageTwo = "Hello from child TWO.\n";

    const unsigned int commLen = strlen(messageOne) + 1;

    char buf[BUF_SIZE];

    if (pipe(pfd1) == -1)
    {
        printf("Error opening pipe 1!\n");
        exit(1);
    }

    if (pipe(pfd2) == -1)
    {
        printf("Error opening pipe 2!\n");
        exit(1);
    }

    printf("Piped opened with success. Forking ...\n");

    // child 1
    switch (fork())
    {
        case -1:
            printf("Error forking child 1!\n");
            exit(1);

        case 0:
            printf("\nChild 1 executing...\n");
            /* close reading end of first pipe */
            if (close(pfd1[0]) == -1)
            {
                printf("Error closing reading end of pipe 1.\n");
                _exit(1);
            }
            /* close writing end of second pipe */
            if (close(pfd2[1]) == -1)
            {
                printf("Error closing writing end of pipe 2.\n");
                _exit(1);
            }

            /* write to pipe 1 */
            if (write(pfd1[1], messageOne, commLen) != commLen)
            {
                printf("Error writing to pipe 1.\n");
                _exit(1);
            }

            if (close(pfd1[1]) == -1)
            {
                printf("Error closing writing end of pipe 1.\n");
                _exit(1);
            }

            /* reding from pipe 2 */
            numRead = read(pfd2[0], buf, commLen);
            if (numRead == -1)
            {
                printf("Error reading from pipe 2.\n");
                _exit(1);
            }

            if (close(pfd2[0]) == -1)
            {
                printf("Error closing reding end of pipe 2.\n");
                _exit(1);
            }

            printf("Message received child ONE: %s", buf);
            printf("Exiting child 1...\n");
            _exit(0);

        default:
            break;
    }

    // child 2
    switch (fork())
    {
        case -1:
            printf("Error forking child 2!\n");
            exit(1);
        case 0:
            printf("\nChild 2 executing...\n");
            /* close reading end of second pipe */
            if (close(pfd2[0]) == -1)
            {
                printf("Error closing reading end of pipe 2.\n");
                _exit(1);
            }
            /* close writing end of first pipe */
            if (close(pfd1[1]) == -1)
            {
                printf("Error closing writing end of pipe 1.\n");
                _exit(1);
            }

            /* read from the first pipe */
            if (read(pfd1[0], buf, commLen) == -1)
            {
                printf("Error reading from pipe 1.\n");
                _exit(EXIT_FAILURE);
            }

            if (close(pfd1[0]) == -1)
            {
                printf("Error closing reading end of pipe 1.\n");
                _exit(EXIT_FAILURE);
            }

            /* write to the second pipe */
            if (write(pfd2[1], messageTwo, commLen) != commLen)
            {
                printf("Error writing to the pipe.");
                _exit(EXIT_FAILURE);
            }

            if (close(pfd2[1]) == -1)
            {
                printf("Error closing writing end of pipe 2.");
                _exit(EXIT_FAILURE);
            }

            printf("Message received child TWO: %s", buf);
            printf("Exiting child 2...\n");
            _exit(EXIT_SUCCESS);

        default:
            break;
    }

    printf("Parent closing pipes.\n");

    if (close(pfd1[0]) == -1)
    {
        printf("Error closing reading end of the pipe.\n");
        exit(EXIT_FAILURE);
    }

    if (close(pfd2[1]) == -1)
    {
        printf("Error closing writing end of the pipe.\n");
        exit(EXIT_FAILURE);
    }

    if (close(pfd2[0]) == -1)
    {
        printf("Error closing reading end of the pipe.\n");
        exit(EXIT_FAILURE);
    }

    if (close(pfd1[1]) == -1)
    {
        printf("Error closing writing end of the pipe.\n");
        exit(EXIT_FAILURE);
    }

    printf("Parent waiting for children completion...\n");
    if (wait(NULL) == -1)
    {
        printf("Error waiting.\n");
        exit(EXIT_FAILURE);
    }

    if (wait(NULL) == -1)
    {
        printf("Error waiting.\n");
        exit(EXIT_FAILURE);
    }

    printf("Parent finishing.\n");
    exit(EXIT_SUCCESS);
}

回答by Aaron Dufour

Your logic is backwards for determining whether a given process is parent or child. The child gets 0from fork, and the parent get the child's pid. Presumably, you want both children to have the same parent, in which case the first ifshould be:

您确定给定进程是父进程还是子进程的逻辑是倒退的。孩子0fork,父母得到孩子的pid。据推测,您希望两个孩子都有相同的父母,在这种情况下,第一个if应该是:

if(chld_1 != 0)

And, the parent should be the process in which both chld_1and chld_2are nonzero:

并且,父进程应该是chld_1chld_2都非零的过程:

if(chld_1 != 0 && chld_2 != 0)

Additionally, you should be error-checking both forks (return of -1 means an error).

此外,您应该对两个forks进行错误检查(返回 -1 表示错误)。