0

我在实验室工作。父进程将创建两个子进程 A 和 B。儿子 A 将通过管道向儿子 B 发送一些字符串。儿子 B 将反转从儿子 A 获得的字符串的字符串大小写,并将反转后的字符串发送回儿子 A.after接收到倒弦的子 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;   
}

问题是当我运行程序时,儿子 B 会被阻止。我需要你们帮助。提前致谢。

4

1 回答 1

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()进程在循环中运行,直到标准输入上的 EOF(如果首先发生)或管道读/写调用之一失败(例如,由于 EOF上input_pipe[0])。由于父级仍在 wait() 调用中等待,并且两个管道的两端都打开,因此管道上没有 EOF(管道上的 EOF 在您读取所有写入者写入的所有数据之后发生,并且所有dups写端已关闭)。所以到达那里的唯一方法是在标准输入上点击 EOF,这样while循环就不会运行。

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

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

  • 创建两个管道(就像你现在做的那样)
  • fork 一次,然后process_A()在 child 中运行
  • 再次分叉(在父级中),并process_B()在(新)子级中运行
  • 关闭两个管道的两端(在父级中)
  • 现在等两个孩子,等两个孩子开始了

kill()错误处理会有点混乱,因为如果你不能启动第二个孩子,你必须做一些事情(比如第一个孩子)。所以你需要知道你已经走了多远。您仍然可以循环到 fork 两次,但您不能wait在循环内,并且只需围绕循环进行两次旅行,每一次执行的步骤都不同,您不妨在没有循环的情况下将其全部写出来。

于 2012-03-19T19:59:59.747 回答