C管道故障(Linux)

时间:2015-04-02 15:06:17

标签: c linux pipe fork ipc

我目前无法理解儿童与其父母之间的非双向双向未命名管道通信。我试图让最多十个孩子与超级父母沟通。

目前我正在努力让超级父母向每个孩子问好,然后孩子们向父母问好。最后,超级父母承认他收到了每个孩子的问候。

我在添加管道之前测试了叉子并且它们工作正常,产生了正确数量的孩子。所以我几乎肯定问题是在我的代码底部的两个pipeCommunication()方法中的一个(或两个)中的某个地方。

当我运行程序时,它静止不动(好像在等待输入)。我预计它会在一段时间内停留在阅读中,但是我甚至无法获得要打印的第一行main()。

以下是代码:

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


int NUM_CHILDREN;
int ID;


// Create the pipes
void createPipes(int[], int[]);

// Wait for the children processes
void waitForChildren(int);

// The Child pipe communication method
void childPipeCommunication(int, int, int);

// The Parent pipe communication method
void parentPipeCommunication(int, int, int);



// MAIN FUNCTION
int main(int argc, char *argv[])
{
    // NOT BEING PRINTED:
    printf("Hello");

    NUM_CHILDREN = argc - 1;

    // The file descriptors for the pipes
    int fd_childReads_ParentWrites[10][2];   // Parent should close 0, Child close 1
    int fd_parentReads_ChildWrites[10][2];   // Child should close 0, Parent close 1

    // Index of the child Array (0 to NUM_CHILDREN-1)
    int user;

    int pid;
    int pidArray[10]; // Stores each of the child's process id's

    // Fork the children and create the pipes
    for(user = 0; user < NUM_CHILDREN; user++)
    {
        // Create the pipes
        createPipes(fd_childReads_ParentWrites[user], fd_parentReads_ChildWrites[user]);

        // Fork the children
        pid = fork();

        if (pid < 0)   // Error occurred
        {
            printf("Fork Failed\n");
            exit(1);
        }
        else if (pid == 0)   // Child
        {
            break;
        }
        else if (pid) // Parent
        {
            pidArray[user] = pid;
        }
    }


    if (pid == 0) // CHILD
    {
        // Close the appropriate pipe ends
        close(fd_childReads_ParentWrites[user][1]);
        close(fd_parentReads_ChildWrites[user][0]);

        ID = getpid();
        int n = 0;

        // Enter pipe communication (user is the same as when it broke from the for loop)
        childPipeCommunication(ID, fd_childReads_ParentWrites[user][0],
                                fd_parentReads_ChildWrites[user][1]);

        // Finally, close the working child pipe ends
        close(fd_childReads_ParentWrites[user][0]);
        close(fd_parentReads_ChildWrites[user][1]);
    }
    else // PARENT
    {
        ID = getpid();
        user = 0;

        // Close the appropriate pipe ends
        for (user = 0; user < NUM_CHILDREN; user++)
        {
            close(fd_childReads_ParentWrites[user][0]);
            close(fd_parentReads_ChildWrites[user][1]);
        }

        // Go into Pipe Communication
        for(user = 0; user < NUM_CHILDREN; user++)
        {
            parentPipeCommunication(pidArray[user], fd_parentReads_ChildWrites[user][0], fd_childReads_ParentWrites[user][1]);
        }

        // Wait for the children
        waitForChildren();

        // Finally, close the working parent pipe ends
        for (user = 0;  user < NUM_CHILDREN; user++)
        {
            close(fd_childReads_ParentWrites[user][1]);
            close(fd_parentReads_ChildWrites[user][0]);
        }
    }
}



void createPipes(int fd1[2], int fd2[2])
{
    if (pipe(fd1) < 0)
    {
        printf("Pipe creation error!\n");
        exit(1);
    }

    if (pipe(fd2) < 0)
    {
        printf("Pipe creation error!\n");
        exit(1);
    }
}


void waitForChildren()
{
    int user;
    for (user = 0; user < NUM_CHILDREN; user++)
    {
        wait(NULL);
    }
}

以下是管道通信的方法。

void childPipeCommunication(int childID, int fdReadFromParent, int fdWriteToParent)
{
    char buf_ChildReads[80];  
    int n = 0;

    while ((n = read(fdReadFromParent, buf_ChildReads, 80)) > 0)
        {
            buf_ChildReads[n] = 0;

            // CASE: CHILD RECEIVES HELLO FROM PARENT
            if(strcmp(buf_ChildReads, "Hi child.\n") == 0)
            {
                // Remove new line character
                buf_ChildReads[--n] = 0;

                // Acknowledge parent's hello and then send reply
                printf("Child %d: Reveived message [%s] from parent\n", childID, buf_ChildReads);
                write(fdWriteToParent, "Hello Parent\n", 13);
            }
        }
}


void parentPipeCommunication(int childID, int fdReadFromChild, int fdWriteToChild)
{
    char buf_ParentReads[80];  
    int n = 0;

    // Say hello to the child
    write(fdWriteToChild, "Hi child\n", 9);

    // Engage in communication with the child
    while ((n = read(fdReadFromChild, buf_ParentReads, 80)) > 0)
        {
            buf_ParentReads[n] = 0;

            // CASE: PARENT RECEIVES HELLO FROM CHILD
            if(strcmp(buf_ParentReads, "Hello Parent\n") == 0)
            {
                printf("Parent: I have received response from child %d\n", childID);
            }
        }
}

如果有人可以查看我的代码并告诉我如何正确实现父母和孩子之间的沟通,我将非常感激。

2 个答案:

答案 0 :(得分:2)

1)问题:printf未打印:

stdout通常在Unix下进行行缓冲。尝试打印到stderr(无缓冲),致电fflush(stdout),或明确打印"\n"

2)问题:写&amp;的strcmp

请注意,write(fd, "Hi child\n", 9)没有尾随'\0',但strcmp会比较零终止字符串。因此,您的孩子流程永远不会回应。

通过管道的双向IPC存在许多缺陷。见https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer

答案 1 :(得分:1)

将NUM_CHILDREN设置为命令行参数的数量。如果你没有提供任何参数,则它为零,没有输入循环,pid未初始化,并且未定义底部的两个路径中的哪一个将被采用。两者都会挂起来。

在您没有从stdin读取并且正在发生挂起的情况下使用printf时,您可能需要使用fflush来获取输出。

接下来,您的父母期待一条没有句号的邮件,并且您的孩子正在发送该句号。

最后,父母和孩子都在循环,直到另一个人关闭,所以来自第一个孩子的沟通不会结束,后来的孩子永远不会被处理。