【问题标题】:C, Piping messages to child processes not working. Why?C,将消息传递给子进程不起作用。为什么?
【发布时间】:2016-02-26 08:51:19
【问题描述】:

我目前正在为我的操作系统课做作业,要求我们编写一个 C 程序,该程序将首先打开四个管道,然后创建 3 个子管道。

然后,父进程将接收来自用户的消息以发送给子进程,并通过管道将它们发送给子进程。然后子进程将显示它们收到的所有消息。

管道 1 将从父级到子级 1。 管道 2 将从父级到子级 2 或 3。 管道 3 和 4 是子级 2 和 3 之间的管道,以确保消息以正确的子级结束。

你的程序应该表现如下:

•   AFTER opening the pipes and creating the children, the parent process should prompt the user for the number of messages to pass. ONLY the parent should have access to this quantity. The children should not be aware of it!

•   Once the parent knows how many messages to expect from the user, it should prompt the user for those messages in the form:
“<message string> <child to receive message>”

•   You may assume that messages are only one word in length (you do not need to handle spaces in messages).

•   The parent will then use pipes P1 and P2 to send all the messages to the appropriate children.

•   Because C2 and C3 share pipe P2, they may receive each other’s messages. In this situation, they are responsible for using P3 or P4 to forward the messages as appropriate.

•   Each process should ensure that its pipes are unidirectional.

•   Once received, messages MUST be printed out in the form
“Child <x> read message: <msg>”
Where <x> is the number of the child (1, 2, 3) that is printing the message and
<msg> is the message itself.

*Hint: To avoid blocking reads in the children, you should consider what happens when processes close one end of a pipe.

*Hint: When sending messages to C2 and C3, you may want to append a special character to the message so that they will know if it was meant for them or not.

*Hint: It’s probably a good idea to perform all the writes before performing any reads.

目前,我的子进程将收到一两条消息,但随后会停止。我认为 read 函数被阻塞了,但我不确定是为了什么,或者为什么。

样本输出:

[root@cmachine CIS370]# ./parksPipes 多少条消息? 3

消息 (1) : ey 1

消息 (2):1 日

消息 (3):哟 1

消息:他们写给孩子 1。

消息:可以写给孩子 1。

消息:你写给孩子 1。

父级退出...

C1 接收:ey

(此时程序挂起。)

代码:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#define MSGSIZE 256

main()
{
    int ppid = getpid(); // Get parent id
    int nmessages = 0;
    int p1[2]; int p2[2]; int p3[2]; int p4[2]; // Arrays used for the pipes
    if(pipe(p1)==-1){printf("p1 err, errno: %d", errno); exit(-1);} if(pipe(p2)==-1){printf("p2 err, errno: %d", errno); exit(-1);}  // Open pipes
    if(pipe(p3)==-1){printf("p3 err, errno: %d", errno); exit(-1);} if(pipe(p4)==-1){printf("p4 err, errno: %d", errno); exit(-1);}

    int kidpid1 = fork();
    if(kidpid1 == 0) // child 1
    {
        int nread;
        char mesg[MSGSIZE];
        close(p1[1]);
        close(p2[0]); close(p2[1]); close(p3[0]); close(p3[1]); close(p4[0]); close(p4[1]);
        while( (nread = read(p1[0], mesg, MSGSIZE))>0) // read will be blocked until write end of pipe closed
        {
              printf("C1 receive: %s\n", mesg);
        }
        printf("Child 1 exiting...\n");
        exit(0);
    }
    else if(kidpid1 > 0) // parent
    {
        int kidpid2 = fork();
        if(kidpid2 == 0) // child 2
        {
            int nread;
            char mesg[MSGSIZE];
            while( (nread = read(p2[0], mesg, MSGSIZE))>0)
            {
                printf("C2 receive: %s\n", mesg);
            }
            printf("Child 2 exiting...\n");
            exit(0);
        }
        else if(kidpid2>0) // parent
        {
            int kidpid3 = fork();
            if(kidpid3 == 0) // child 3
            {
                    close(p2[1]);
                    int nread;
                    char mesg[MSGSIZE];
                    while( (nread = read(p2[0], mesg, MSGSIZE))>0)
                    {
                        printf("C3 receive: %s\n", mesg);
                    }
                    printf("Child 3 exiting...\n");
                    exit(0);
            }
            else if(kidpid3 > 0) // parent
            {
                close(p1[0]); close(p2[0]); close(p3[0]); close(p4[0]); // Close all the read ends of the pipes (parent will not be reading)
                close(p3[1]); close(p4[1]); // Close the write ends of pipes 3 and 4 (parent will not be writing down these pipes)
                printf("How many messages? ");
                scanf("%d", &nmessages);
                char *msg[nmessages];
                 int child[nmessages];
                 int i=0;
                for(i=0; i<nmessages; i++)
                {
                    printf("Enter message (%d) <message string> <child to receive message>: ", i+1);
                    scanf("%s %d", &msg[i], &child[i]);
                    //printf("%s %d", &msg[i], child[i]); // Parrot the message back for debugging purposes
                }
                for(i=0; i<nmessages; i++)
                {
                    switch(child[i])
                    {
                        case 1: // send msg[i] to child 1 (p1)
                        if(write(p1[1],&msg[i],sizeof(msg[i]))== -1)
                        {
                            perror("Pipe 1 write error. errno: %d\n");
                            exit(-1);
                        }
                        else
                          printf("Message : %s written to Child %d.\n", &msg[i], child[i]);
                        break;
                        case 2: // send msg[i] to child 2 (p2) (p2 goes to C2 and C3, p3 and p4 is between the two children)
                        if(write(p2[1],&msg[i],sizeof(msg[i])) < 0)
                        {
                            printf("Pipe 2 write error. errno: %d\n", errno);
                            exit(-1);
                        }
                        break;
                        case 3: // send msg[i] to child 3 (p2)
                        if(write(p2[1],&msg[i],sizeof(msg[i])) < 0)
                        {
                            printf("Pipe 1 write error. errno: %d\n", errno);
                            exit(-1);
                        }
                        break;
                        default:
                        printf("Incorrect child ID entered: %d", child[i]);
                        exit(-1);
                        break;
                    }
                }
                close(p1[1]); // Close write end of Pipe 1
                close(p2[1]); // Close write end of Pipe 2
                printf("Parent exiting...\n");
            }
            else
            {printf("Err ln35, errno: %d", errno); exit(-1);}
        }
        else // error
        {printf("Err ln18, errno: %d", errno); exit(-1);}
    }
    else // error
    {printf("Fork err, ln 75. errno: %d", errno); exit(-1);}
}

【问题讨论】:

  • 从管道读取时,只有在管道为空时才会阻塞读取,即没有任何内容写入其中。

标签: c linux unix centos6


【解决方案1】:

您的代码中有未定义的行为。您有一个指向字符 msg 的指针数组,并且在读取用户输入时使用该数组。

这里的第一个问题是数组中的指针未初始化。未初始化的局部变量的值是 indeterminate 并且以任何方式使用它们,除了初始化它们会导致未定义的行为。要么为这些指针动态分配内存,要么使用字符数组数组,例如

char msg[nmessages][MAX_MESSAGE_LENGTH];

第二个问题是如何在scanf 调用中使用数组msg。当您执行&amp;msg[i] 时,您会得到一个指向该指针 的指针,即您得到一个char **,这与我猜想的不完全一样?如果您将msg 更改为数组数组,此问题将自行解决,但也可以通过删除地址运算符并将msg[i] 传递给scanf 来解决。

【讨论】:

  • 谢谢!这个回复非常详细和描述性。我一直在 C 语言中遇到字符串问题,因为我在大一那年对编程课的介绍由于时间不足而最终没有涵盖它们。我曾考虑使用 char 数组来接收消息,但不确定如何去做,并且确信我的指针想法会奏效。这个答案很完美。
猜你喜欢
  • 2010-11-04
  • 1970-01-01
  • 2015-09-09
  • 1970-01-01
  • 1970-01-01
  • 2022-10-12
  • 1970-01-01
  • 2015-06-03
  • 1970-01-01
相关资源
最近更新 更多