4

編集:write()したがって、追加のデバッグにより、EOFはパイプに正常に書き込まれます(関数が で 0 を返すことを確認するためにテストしたため、これを知っていproduceStdinます。ただし、同じパイプから読み取ると、 EOFに遭遇したと表示されます(良い) しかし、EOF 要素の値は 255 に等しい (通常のように -1 ではなく) なぜこれが当てはまるのか誰か知っていますか?

このプログラムを作成しようとしていますが、stdin から EOF が発生した場合、パイプに -1 が書き込まれません。なんらかの理由で、パイプ経由で EOF を渡そうとすると、ガベージが書き込まれ、後続のすべてのプロセスが無限ループに陥ります。

関数内の配列を出力するもの以外のすべてのprintステートメントは、printOut()私がデバッグしようとしているものです(フォークのためにデバッガーを使用できません)

また、これらのコメントの一部はリサイクルされているため、「バッファー」について言及されている場合は、パイプではなくバッファーを使用して以前にプログラムされたためです。

コードは次のとおりです。

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

#define MAX_CHARS 81 //80 chars + null-terminator
#define NUM_CHILDREN 3

void produceStdin(int writePipe);
void child1(int readPipe, int writePipe);
void child2(int readPipe, int writePipe);
void printOut(int readPipe);

int main(int argc, char const *argv[])
{
    int i,pipe1[2],pipe2[2],pipe3[2];
    pid_t childPid;

    if(pipe(pipe1)==-1||pipe(pipe2)==-1||pipe(pipe3)==-1)
    {
        fprintf(stderr, "Error in creating pipe");
    }
    //despite what it looks like only four children are being forked,
    // all to the same parent. The children get called to their respective 
    //functions where they get terminated before getting to fork themselves.
    for(i=0;i<NUM_CHILDREN;i++)
    {
        childPid=fork();
        switch (childPid) {
            case -1:
                perror("fork() failed. Aborting.");
                exit(EXIT_FAILURE);

            case 0:
                switch (i) {
                    case 0:
                        close(pipe1[0]); //close pipe1 read (since we're reading from stdin)

                        close(pipe2[0]); //close pipe2
                        close(pipe2[1]);

                        printf("right before calling stdin i=%d\n",i);
                        produceStdin(pipe1[1]); //write to pipe1
                        break;

                    case 1:
                        close(pipe1[1]); //close pipe1 write

                        close(pipe2[0]); //close pipe2 read

                        close(pipe3[0]); //close pipe3
                        close(pipe3[1]);
                        printf("right before calling child1 i=%d\n",i);
                        child1(pipe1[0], pipe2[1]); //read from pipe1, write to pipe2
                        break;

                    case 2:
                        close(pipe1[0]); //close pipe1
                        close(pipe1[1]);

                        close(pipe2[1]); //close pipe2 write

                        close(pipe3[0]); //close pipe3 read
                        printf("right before calling child2 i=%d\n",i);
                        child2(pipe2[0], pipe3[1]); //read from pipe2, write to pipe3
                        break;

                    default:
                        break;
                }

            default:
                if(i==2)
                {
                    close(pipe1[1]); //close pipe1
                    close(pipe1[0]);

                    close(pipe2[1]); //close pipe2
                    close(pipe2[0]);

                    close(pipe3[1]); //close pipe3 write

                    printOut(pipe3[0]); //read from pipe3 read
                }
                break;
        }
    }
    return 0;
}
void produceStdin(int writePipe)
{
    int c=0;
    while(c!=EOF)
    {
        c=fgetc(stdin);
        write(writePipe, &c, sizeof(char)); //writing EOF here is where the problem starts I believe
    }
    printf("Got EOF in ProdStdin\n");
    printf("EOF has a value of: %d",c);
    exit(0);
}
void child1(int readPipe, int writePipe)
{
    int c=0;
    while(c!=EOF)
    {
        read(readPipe,&c,sizeof(char));
//        printf("Child1 got a char from pipe1: %c\n",c);
        if(c=='\n')
        {
            c=' '; //test for newline
        }
        write(writePipe, &c, sizeof(char));
    }
    exit(0);
}
void child2(int readPipe, int writePipe)
{
    int c=0;
    int c2=0;
    while(c!=EOF && c2!=EOF)
    {
        read(readPipe, &c, sizeof(char));
//        printf("Child2 got a char from pipe2: %c\n",c);
        if(c=='*')
        {
            read(readPipe, &c2, sizeof(char)); //if c is a * remove another char
            if(c2=='*')
            {
                c='^'; //if c2 is a * then put a ^ on buffer3
                write(writePipe,&c,sizeof(char));
            }
            else
            {
                write(writePipe,&c,sizeof(char));
                write(writePipe,&c2,sizeof(char));
            }
        }
        else
        {
            write(writePipe,&c,sizeof(char));
        }
    }
    exit(0);
}
void printOut(int readPipe)
{
    int c=0,numChars=0;
    char output[MAX_CHARS];
    while (c!=EOF)
    {
        read(readPipe, &c, sizeof(char));
//        printf("PrintOut got a char from pipe3: %c\nnumChars= %d\n",c,numChars);
        if (numChars==MAX_CHARS-2)
        {
            printf("%s\n",output);
            memset(output, '\0', sizeof(char)*MAX_CHARS);
            numChars=0;
        }

        output[numChars]=c;
        numChars++;
    }
    printf("ABOUT TO EXIT PRINTOUT()\n");
    exit(0);
}
4

2 に答える 2

2

パイプ を介して読み取られたものの 2 バイト バージョンを渡すと、受信側で char と EOF を区別できます。

int c = 0;
while(c!=EOF) {
  c = fgetc(stdin);
  short sc = (short) c;
  // `sc` will _typically_ have the values -1 (EOF) and 0,1,2,... 255.
  write(writePipe, &sc, sizeof(sc));
}

int c=0;
int c2=0;
while(c != EOF && c2 != EOF) {
  short sc;          
  if (sizeof(sc) != read(readPipe, &sc, sizeof(sc))) handle_error();
  // `sc` will _typically_ have the values -1 (EOF) and 0,1,2,... 255.
  c = sc;
  ...

の提案された回答。

cすべての文字が読み取られるまで EOFなりません。
使用する:

// while(c!=EOF) {
//   c=fgetc(stdin);
//   write(writePipe, &c, sizeof(char));
// }
while((c = fgetc(stdin)) != EOF) {
  write(writePipe, &c, sizeof(char));
}

の戻り値は、EOF になることread(readPipe, &c, sizeof(char));を探す代わりに評価する必要があります。cEOF は a に収まりませんchar

// int c=0;
// int c2=0;
// while(c!=EOF && c2!=EOF) {
//    read(readPipe, &c, sizeof(char));

char c=0;
char c2=0;
while(1 == read(readPipe, &c, sizeof(char))) {

于 2013-10-15T19:55:02.820 に答える
0

このビットは、コードの記述に問題があります。

int c = 0;

while(c!=EOF)
{
    c=fgetc(stdin);
    write(writePipe, &c, sizeof(char));
}

以下を使用する必要があります。

int c;

while ((c = fgetc(stdin)) != EOF)
{
    char c1 = c;
    write(writePipe, &c1, sizeof(char));
}

からの出力は、または EOFfgetc()として返される符号なし文字値です。intそのままでは、EOF を検出し、実際に書き込むべきではないバイトをパイプに書き込みました。の使用はc1一般に必要です。リトル エンディアン マシンで書いたものはおそらく問題なく動作しますが、ビッグ エンディアン マシンでは正しく動作しません。おそらく、書き込みが成功することも確認する必要があります。

同等の読み取りコードにも同様の問題があります。あなたが持っている:

int c=0;
while(c!=EOF)
{
    read(readPipe,&c,sizeof(char));
    if(c=='\n')
    {
        c=' '; //test for newline
    }
    write(writePipe, &c, sizeof(char));
}

必要なもの:

char c;
while (read(readPipe, &c, sizeof(char)) == sizeof(char))
{
    if (c == '\n')
        c = ' ';
    write(writePipe, &c, sizeof(char));
}

繰り返しますが、リトルエンディアンとビッグエンディアンの移植性の問題と、入力操作のテストがありました (常に、しかし常に入力操作を確認してください。出力を確認せずに済むことがよくありますが、常に入力を確認する必要があります)。 .

read()およびを介した 1 文字の I/Owrite()は、高性能アプリケーションではコストがかかることに注意してください。標準 I/O 1 文字の I/O は、入力または出力をバッファリングし、読み取りごとおよび書き込みごとにシステム コールのオーバーヘッドを発生させないため、問題ありません。おもちゃのアプリケーションの場合、オーバーヘッドに気付かないでしょう。

これは、わずかに異なる方法で表現された、chuxが答えで言ったことかもしれません。

于 2013-10-15T21:15:31.557 に答える