0

かなり単純なことだと思いますが、私の人生では、子プロセスが機能せず、待機し、最後のプロセスが一時停止している理由を理解できません(パイプを適切に閉じていないなど)。とにかく、私はたくさんのコードを投稿しますが、これはそれがしていることです:

  1. プログラムはtxtドキュメントを解析し、すべての個々の単語を取得して、パイプラウンドロビンスタイルで指定された数の子プロセスに送信します。パイプFDを保持する1次元配列があり、すべての偶数インデックスが読み取りであり、すべての奇数インデックスが書き込みパイプです。

  2. 解析が終了した後、プログラムは子をフォークする前に読み取り/書き込みパイプを閉じます(親とのパイプを閉じるため)。次に、forループ内で、指定された数の子プロセスが生成され、対応するパイプの書き込み端が子で閉じられ、読み取り端が開かれます。fgetsは、パイプから入力を取得するために使用する必要があります(私は知っています、迷惑ですが、それは要件です)。

  3. 子が完了すると、親プロセスによって待機されます。私が助けてくれたコメントとデバッガーの行がいくつかあり、それらから、子プロセスがフォークされて正しく入力され、書き込みパイプが閉じられ、読み取りパイプが開かれているように見えますが、 fgets()関数は、すぐに終了し、親によって待機されます。興味深いことに、すべての子供たちが待たされるわけではありません。子の数を3にしたい場合は、2つのプロセスが待機され、3番目のプロセスがハングアップします。10個のプロセスが必要な場合、5個が待機し、6個目がハングアップします。

ですから、fgets()と関係があると確信していますが、その理由はわかりません。私は、改行文字がパイプに沿って送信されたときに間違った場所にあることに関係しているかもしれませんが(fgetsは改行まで読みますよね?)、書かれたコードといくつかの追加のデバッグステートメントに基づいています親プロセスからのパイプは、改行が適切に終了しているようです。

とにかく、これがパーサーと子の作成に関するビットの両方のコードです-

パーサー:

char buf[PIPE_BUF];     
int wordCount;

char buffer[PIPE_BUF];
char *temp;
char word[50];
FILE* inputFile = fopen(fileName,  "r"); //OPENS file
//Parsing and distributing words round robin to pipes
while(fgets(buffer, (sizeof buffer), inputFile)){
    //remove all non-alpha chars in buffer and converts to lowercase
    int i;
    for(i = 0; i < strlen(buffer); i++){
        if(isalpha(buffer[i]) == 0){ //0 means it is not a letter
            buffer[i] = ' ';
        }
        else{
            buffer[i] = tolower(buffer[i]); //turn the current word to lower case
        }
    }
    //parse words and sends them to the sort processes in a round-robin fashion
    temp = strtok(buffer, " "); //splits along spaces
    if(temp != NULL){
        strcpy(word, temp);
        strcat(word, "\n"); //puts newline at the end
    }
    int j = 0;
    while(temp != NULL){
        FILE *input = fdopen(pipefds[(j*2)+1], "w");
        //close(pipefds[j*2]); //closing read pipes in parent
        fputs(word, input); //puts into write pipe
        printf("fputs done successfully with pipe %d with contents: %s\n", pipefds[(j*2)+1], word);
        //close(pipefds[(j*2)+1]); //closing write pipe after write is done
        temp = strtok(NULL, " ");
        if(temp != NULL){
            strcpy(word, temp);
            strcat(word, "\n");
        }
        if(j == (numChildren - 1)){
            j = 0;
        }
        else{
            j++;
        }
    }
}
//need to close all parent writes, and parent reads (it's done with everything)
for(i = 0; i < numChildren; i++){
    close(pipefds[i]);
}

親のフォークとパイプデータの取得:

//Collection of children need to be created specified by numChildren
int count;
for(count = 0; count < numChildren; count++){
    printf("Count: %d\n", count);

    switch((p = fork())){

    case -1:
        perror("Could not create child");
        exit(-1);

    case 0:
        printf("Entering child\n");
        //child case, GET INPUT FROM PARENT TO SORT!!! SEND TO SUPPRESSOR (Uses both input and output)
        //count[0] = read, count[1] = write
        close(pipefds[(count*2)+1]); //closing write pipes in child
        printf("write pipe closed in child\n");
        FILE *output = fdopen(pipefds[count*2], "r"); //opening the read pipe from the parent write pipe
        printf("read pipe opened in child\n");
        fgets(buf, PIPE_BUF, output); //gets data from read pipe
        printf("child read pipe contents read (fgets) with buf contents: %s\n", buf);
        printf("child read pipe closed (%d)\n", getpid());
        //execlp("sort", "sort", sortStuff,(char*)NULL);
        close(pipefds[count*2]); //closing read pipe after reading is done
        count = numChildren;
        break;

    default:
        //parent case -- p holds pid of child

        printf("I am the parent, PID: %d\n", getpid());
        child = wait(&status);
        printf("Waited on child %d\n", child);

        break;
    }

}

私はコードについて事前に謝罪します。私は最高のCプログラマーではないので、物事は少し厄介になる傾向があります。

4

2 に答える 2

1

主な問題はこのコードにあります:

// need to close all parent writes, 
// and parent reads (it's done with everything)

for(i = 0; i < numChildren; i++){
  close(pipefds[i]);

子プロセスを作成する前にこれを行い(表示されます)、そうすることで、基本的にパイプを削除します。彼らは行ってしまいました。それらはもう存在しません。子プロセスが読み取るものは何もありません。私の推測では、この行は次のとおりです。

FILE *output = fdopen(pipefds[count*2], "r");

ファイル記述子がすでに閉じられているために失敗しています(出力はNULLです)。したがって、システムに関する限り、は無効な記述子です。

もう1つの問題は、ステップの順序です。通常、パイプを作成してから子プロセスを作成します。子プロセスが終了して初めて、パイプを閉じます。パイプに書き込み、そこから読み取る子プロセスを作成する実装を見たことがないと思います。これには大きな問題が1つあります。パイプのサイズが制限されており、親プロセスが書き込みをブロックする可能性があるためです。パイプへ(テストしている小さなファイルがあり、パイプのサイズ制限に達していないようです)。

私がお勧めする手順の順序は次のとおりです。

create the pipes
create the child processes
in the parent process
    close the read end of each pipe (only the read end)
    read the text file
    write words to the pipes
    when done reading text file, close the write end of each pipe
    wait for each child 
in the child process(es)
    close the write end of the pipe its using
    while there is input from the pipe
      read the input
      do whatever
    close the read end of the pipe
    _exit()

そうすれば、実際にマルチプロセッシングのメリットを享受でき、書き込み時に親が無期限にブロックすることを心配する必要がなくなります(子プロセスの読み取りが常に存在するため)。

于 2013-02-19T23:12:16.513 に答える
0

この関数を使用してFILE*を記述子に関連付ける場合:

ファイル*input= fdopen(pipefds [(j * 2)+1]、 "w");

次に、* inputで行うことはすべて、パイプ内で行われるバッファリングに加えてバッファリングされます。したがって、パイプに書き込んでいると思われるものが、実際にはFILE *のバッファーにあるだけで、実際にはパイプに到達していない可能性があります。fclose(input)を使用した場合、バッファーは最後にフラッシュされますが、FILE *ではなく、基になるファイル記述子を閉じていると思います。つまり、FILE*のすべてのバッファー管理はそれが終了する必要があることを認識していません。上。

fflush(input)の呼び出しが役立つ場合があります。

これとは別に、さらに深く、読み取りを開始する前にすべてのデータをパイプに書き込んでいる場合は、パイプがそれ以上の入力を受け入れなくなる前に、パイプがバッファリングできるものに制限があることに注意する必要があります(もう一方の端から何かが読み取られます。)

編集:要約すると、データがFILE *バッファーにスタックしていて、パイプに到達することさえないと思います。フラッシュされません。また、おそらくどこかでfclose(input)を呼び出す必要があります。これは、基になるファイル記述子をclose()する必要性に影響します。

于 2013-02-19T21:24:55.007 に答える