Нужна помощь в IPC через Pipes - PullRequest
0 голосов
/ 19 марта 2012

Я работаю в лаборатории.Отчий процесс создаст два дочерних процесса A и B. Сын A отправит некоторую строку сыну B через pipe.son B инвертирует строковый регистр строки, полученной от сына A, и отправит обратно инвертированную строку сыну A.afterПолучив перевернутую строку, сын А распечатает ее на экране.

вот код.

#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;   
}

проблема в том, что когда я запускаю программу, сын Б получает блок.Ребята, вам нужна помощь.Заранее спасибо.

1 Ответ

2 голосов
/ 19 марта 2012

ОК, диаграмма:

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 на stdin (если этопроисходит первым) или один из вызовов чтения / записи канала завершается неудачно (например, из-за EOF на input_pipe[0]).Поскольку родительский объект все еще ожидает вызова wait (), и оба конца обоих каналов открыты, EOF в канале (EOF в канале возникает после того, как вы прочитали все данные, записанные всеми авторами, и все dupс конца записи были закрыты).Таким образом, единственный способ добиться этого - нажать EOF на stdin, чтобы цикл while не запускался.

Во-вторых, если вам удастся снова разветвляться и делать process_B(), этот ребенок будеттакже ждите вечно, потому что один конец записи канала, из которого он читает, все еще открыт ... в родительском!Родитель не закроет его, потому что родитель будет ждать вечно в wait.

В общем, что вам нужно сделать здесь:

  • создать два канала (как вы делаете сейчас)
  • fork один раз, и запустите process_A() в дочернем
  • fork снова (в родительском), и запустите process_B() в (новом) дочернем
  • закрыть оба конца обоих каналов (в родительском элементе)
  • дождаться обоих потомков, после оба запустились

Обрабатывается ошибканемного грязно, так как вы должны что-то сделать (например, kill() первый ребенок), если вы не можете запустить второго ребенка.Так что вам нужно знать, как далеко вы продвинулись.Вы по-прежнему можете выполнять цикл с разветвлением дважды, но вы не можете wait внутри цикла, и всего за два обхода цикла, каждый из которых выполняет довольно разные шаги, вы можете просто записать все это без цикла.

...