需要帮助IPC通过管道

时间:2012-03-19 19:27:56

标签: unix operating-system ipc multiprocessing inter-process-communicat

我在实验室工作。 父进程将创建两个子进程A和B. Son A将通过pipe发送一些字符串到子B.son B将反转字符串从字母A得到的字符串案例,并将反向字符串发送给儿子A.收到反向字符串后,儿子A将其打印到屏幕

这是代码。

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

void process_A(int input_pipe[], int output_pipe[])
{
    int c;    
    char ch; 
    int rc;  


    close(input_pipe[1]); 
    close(output_pipe[0]); 

    while ((c = getchar()) > 0) {
        ch = (char)c;
        rc = write(output_pipe[1], &ch, 1);
    if (rc == -1) { 
        perror("A_TO_B: write");
        close(input_pipe[0]);
        close(output_pipe[1]);
        exit(1);
        }

    rc = read(input_pipe[0], &ch, 1);
    c = (int)ch;
    if (rc <= 0) { 
        perror("A_TO_B: read");
        close(input_pipe[0]);
        close(output_pipe[1]);
        exit(1);
        }
    putchar(c);
    }
    close(input_pipe[0]);
    close(output_pipe[1]);
    exit(0);
}

void process_B(int input_pipe[], int output_pipe[])
{
    int c;   
    char ch; 
    int rc;   
    close(input_pipe[1]); 
    close(output_pipe[0]); 
    while (read(input_pipe[0], &ch, 1) > 0) {
        c = (int)ch;
        if (isascii(c) && isupper(c))
            c = tolower(c);
          else if (isascii(c) && islower(c))
            c = toupper(c);
        ch = (char)c;
        rc = write(output_pipe[1], &ch, 1);
        if (rc == -1) {
            perror("B_TO_A: write");
            close(input_pipe[0]);
            close(output_pipe[1]);
            exit(1);
        }
    }

    close(input_pipe[0]);
    close(output_pipe[1]);
    exit(0);
}


int main(int argc, char* argv[])
{
    /* 2 arrays to contain file descriptors, for two pipes. */
    int A_TO_B[2];
    int B_TO_A[2];
    int pid;       
    int rc,i,State;       

    /* first, create one pipe. */
    rc = pipe(A_TO_B);
    if (rc == -1) {
    perror("main: pipe A_TO_B");
    exit(1);
    }
    /* create another pipe. */
    rc = pipe(B_TO_A);
    if (rc == -1) {
    perror("main: pipe B_TO_A");
    exit(1);
    }

    for(i=0;i<2;i++)
    {
        if((pid=fork()) <0){perror("fork failed\n");};
        if((i==0) && (pid ==0))
        {
            process_A(A_TO_B, B_TO_A); 
        }
        else if((i==1)&&(pid==0))
        {
            process_B(B_TO_A, A_TO_B); 
        }
        else if(pid>0)
        {
           wait( &State );          
        }   
    }

    return 0;   
}

问题是当我运行程序时,Son B得到​​Block。 我需要你们的帮助。 提前谢谢。

1 个答案:

答案 0 :(得分:2)

好的,图表:

initially: parent process: has
  B_TO_A[0] and [1] open,
  has A_TO_B[0] and [1] open
fork (makes copy)
parent:                                child (pid==0):
B_TO_A both open, A_TO_B both open     call process_A: close unwanted pipe ends, loop

call wait(), wait for one child        loop reads stdin, writes one pipe, reads other pipe

if we ever get here:

fork (makes copy)
parent:                                child (pid==0):
B_TO_A both open, A_TO_B both open     call process_B: close unwanted pipe ends, loop

parent: both ends of both pipes open
call wait(), wait for one child        loop reads one pipe, writes other pipe

首先,你通常不会得到“如果我们到达这里”,因为运行process_A()的子进程在循环中运行,直到stdin上的EOF(如果首先发生)或其中一个管道读/写调用失败(例如,由于input_pipe[0]上的EOF)。由于父进程仍在wait()调用中等待,并且两个管道的两端都打开,管道上没有EOF(在读取所有编写器写入的所有数据之后,管道上出现EOF,并且{{1写端的s已经关闭)。所以到达那里的唯一方法是在stdin上点击EOF,这样dup循环就不会运行了。

其次,如果你再次开始分叉并做while,那个孩子也将永远等待,因为它正在读取的管道的一个写端仍然是......在父母中!父母不会关闭它,因为父母将永远等待process_B()

一般来说,你需要做的是:

  • 创建两个管道(就像你现在一样)
  • 分叉一次,并在孩子中运行wait
  • 再次
  • fork(在父级中),并在(新)子级
  • 中运行process_A()
  • 关闭两个管道的两端(在父级中)
  • 现在等待两个孩子, 两个孩子都已经开始

错误处理有点乱,因为如果你不能启动第二个孩子你必须做某事(例如process_B()第一个孩子)。所以你需要知道你走了多远。你仍然可以循环到fork两次,但你不能在循环中kill(),并且只需要绕循环两次,每次都执行相当不同的步骤,你也可以在没有循环的情况下全部写出来