3

免責事項:これは割り当て用です。私は明示的なコードを求めていません。他の人がやったことを真似せずに資料を学ぶことができるように、私は概念を理解する助けを求めているだけです。

私の任務は、テキストファイルからデータを取得し、単語を解析し、アルファベット順に並べ替え、重複を削除して、新しいテキストファイルに出力することです。これは、IPC用のパイプを使用して、3つのプロセスを使用して実行されます。パイプやIPCを扱ったのはこれが初めてなので、少し初心者に出くわした場合は、ご理解ください。

そこで、main関数をinput / parent、sort(child)、output(grandchild)の3つのプロセスにフォークしました。親プロセス内にIOストリームを作成し、それをソートプロシージャにパイプする必要があります。そのパイプを作成し、未使用の端を閉じました(stdin入力stdout用、並べ替え用)。

私の問題はこれです:IOバッファからパイプ(stdoutで)にデータを移動する方法がわかりません。fputs解析された単語リストが一度に1つの単語に渡される、を使用する必要があるように感じstdoutます。

以下は、入力プロシージャ用にこれまでに作成したものです。ファイルIOは私の強みではないので、エラーが発生した場合はお知らせください。できる限り修正します。ご協力ありがとうございました!

} else {                            /* This is the input/parent process */

    printf("This is the input process\n");

    close(input_to_sortFD[0]);      /*  
                                     * Closes the parent-side read-end of
                                     * the pipe 
                                     */

    pipeStream = fdopen(input_to_sortFD[1], "w"); /* 
                                                   * Buffer that feeds into
                                                   * write-end of pipe
                                                   */


    ioFileFD = fopen(ioFile, "r");
    if (ioFileFD == NULL) {
        perror("Fatal error: failed to open requested file");
        exit(-1);
    }

    int i = 0;

    while (fscanf(ioFileFD, "%s", wordList) != EOF) {
        fputs(wordList[i], stdout);
        i++;
    }
}
4

2 に答える 2

2

あなたの問題は:

データをIOバッファーからパイプ(stdout)に移動する方法がわかりません。

私が集めたものから、あなたは問題を考えすぎています。FILE *からの読み取りとへの書き込みの方法を知っている場合FILE *、パイプについて特別なことは何もありません。

私はこのようにプログラムを構成します:

  • 親プロセス
    • 入力ファイルと出力ファイルを開き、パイプを作成します
    • 子プロセス「wordify」を起動します
    • 子プロセス「sortunique」を起動
    • 子供たちが終わるのを待つ
  • 言葉化プロセス
    • 入力を読み取り、単語を書き込みます
  • 独自のプロセス
    • 単語を読み取り、一意のオカレンスを並べ替えて、結果のリストを出力します

sedとを使用して、「wordify」プロセスと「sortunique」プロセスのプロトタイプを作成できsortます。以下のプロトタイプは、単語をアルファベット文字の連続した出現であると定義しています。

void wordify (FILE *infile, FILE *outfile)
{
    int r;
    make_stdio(infile, outfile);
    r = execlp("sed", "sed", "-e",
               "s/[^a-zA-Z][^a-zA-Z]*/ /g;s/^ *//;s/ *$//;/^$/d;s/ /\\n/g",
               (char *)0);
    assert(r == 0);
}

void sortunique (FILE *infile, FILE *outfile)
{
    int r;
    make_stdio(infile, outfile);
    r = execlp("sort", "sort", "-u", (char *)0);
    assert(r == 0);
}

プロトタイプはを使用するため、execlp()infileマップする必要がstdinあり、にマップoutfileする必要がありますstdout。これはで実現dup2()されますが、を処理するラッパー関数を実装しfdup2()ますFILE *

FILE * fdup2 (FILE *oldstream, FILE *newstream)
{
    if (newstream) {
        if (fileno(oldstream) != fileno(newstream)) {
            if (dup2(fileno(oldstream), fileno(newstream)) < 0) return 0;
            fclose(oldstream);
        }
        return newstream;
    }
    return oldstream;
}

void make_stdio (FILE *infile, FILE *outfile)
{
    FILE *x = fdup2(infile, stdin);
    FILE *y = fdup2(outfile, stdout);
    assert(x && y);
}

プロセスはfork()期待どおりに起動されます。

void launch (void (*func)(FILE *, FILE *), FILE *infile, FILE *outfile)
{
    assert(infile && outfile);
    switch (fork()) {
    case -1: perror("fork");
             exit(EXIT_FAILURE);
    case 0:  func(infile, outfile);
             exit(EXIT_SUCCESS);
    default: fclose(infile);
             fclose(outfile);
    }
}

これで、メインプログラムは、入力ファイルと出力ファイルを開き、パイプを作成し、プロセスを起動して、プロセスが終了するのを待つだけです。唯一のトリックは、パイプの書き込み端がの出力であり、パイプwordifyの読み取り端がの入力になるようにパイプを使用する必要があることですsortunique

int main (int argc, char *argv[])
{
    FILE *infile;
    FILE *outfile;
    int pipefds[2];
    int r;

    if (argc < 3) {
        fprintf(stderr, "need input and output filenames\n");
        exit(EXIT_FAILURE);
    }

    if ((infile = fopen(argv[1], "r")) == 0) {
        perror(argv[1]);
        exit(EXIT_FAILURE);
    }

    if ((outfile = fopen(argv[2], "w")) == 0) {
        perror(argv[2]);
        exit(EXIT_FAILURE);
    }

    r = pipe(pipefds);
    assert(r == 0);

    launch(wordify, infile, fdopen(pipefds[1], "w"));
    launch(sortunique, fdopen(pipefds[0], "r"), outfile);
    while (waitpid(-1, 0, 0) == 0) {}

    return 0;
}

合計3つのプロセスが参加していることに注意してください。3つ起動する必要があり、4つのプロセスが参加している場合は、とに分割することを検討sortuniquesortますunique

    r = pipe(pipefds1);
    assert(r == 0);
    r = pipe(pipefds2);
    assert(r == 0);

    launch(wordify, infile, fdopen(pipefds1[1], "w"));
    /* sort: behaves like "sort" command with no arguments */
    launch(sort, fdopen(pipefds1[0], "r"), fdopen(pipefds2[1], "w"));
    /* unique: behaves like "uniq" command with no arguments */
    launch(unique, fdopen(pipefds2[0], "r"), outfile);
    while (waitpid(-1, 0, 0) == 0) {}

問題をこれらのコンポーネントに分解したら、特定のコンポーネントの実装に取り​​組むことは、単なる標準的な読み取り入力と書き込み出力の演習です。パイプの問題は、ファイルストリームが適切な順序で配置され、コンポーネントが読み取りと書き込みを行うだけで抽象化されます。make_stdio()コードを削除して、から読み取り、infileに書き込むこともできoutfileます。

于 2013-02-25T05:27:03.223 に答える
0

通常、パイプ通信はread()およびwrite()呼び出しで行われます。しかし、fscanfやその仲間を使用できるように、intファイル記述子をFILE*に昇格させているようです。

読み取りにfscanf()を使用している場合は、書き込みにfprintf()を使用できます。

于 2013-02-20T23:44:00.760 に答える