0

私は、N個の子(マップ)+ 1(縮小)を生成する親を持つ古典的なマップ縮小プログラムを実装しています。親は、名前のないパイプを介して、N 個の子のそれぞれに情報を送信します。マップはリクエストを処理し、結果の int を reduce に送信します。reduce は select を実行し、map から reduce へのパイプに書き込まれたすべてのカウンターを合計します。

最後に、reduce は結果とともにシグナル SIGUSR1 を送信する必要がありますが、シグナル ハンドラで常に o を出力するため、コードは何度も間違って送信します。コードの一部です:

void reduce() {

    int answer;
    int i = 0;
    fd_set set;
    FD_ZERO(&set); //clean set of pipes

    while (1) {
        for (i = 0; i < maps_nr; i++) {
            FD_SET(fd_maps_to_reduce[i][READ], &set); 
        }
        if (select(FD_SETSIZE, &set, NULL, NULL, NULL) > 0) {
            printf("Entrou no select\n");
            for (i = 0; i < maps_nr; i++) { 
                if (FD_ISSET(fd_maps_to_reduce[i][READ], &set)) {
                    close(fd_maps_to_reduce[i][WRITE]);
                    if (read(fd_maps_to_reduce[i][READ], &answer, sizeof (int))) {
                        result += answer;
                        printf("Result in reduce =%d\n", result);
                    } else {
                        printf("Reduce failed to read from pipe from son :%d!\n", i);
                    }
                }
            }
        }//end of select
        printf("Reduce is going to send a signal with result= %d!\n", result);
        kill(getppid(), SIGUSR1);
        printf("Already send!\n");
    }
}

親では、パイプと子を作成した後、次のようなものがあります。

(...)
signal(SIGUSR1, handle_signal);
while(exit) {
    (...)//this is a menu
    for i->N 
        send a struct to each child (through write in respective pipe)
    after the for do:
    pause();//waiting for a signal to be caught
    if (errno==EINTR)
       printf("caught sigusr1");
}

void handle_signal(int signum) {
    signal(SIGUSR1, handle_signal);
    //print results
    printf("Result: %d\n",result);
}

問題は、削減プロセスが正しく合計され、正しく出力されることですが、シグナルが何度も送信されているため、1 つだけが必要です。グローバル変数の結果。

どうやってやるの?reduce に何か問題がありますね。

4

1 に答える 1

1

まず、次のような見栄えの良い select() ループを作成できます。

while (newfds = readfds, select(n, &newfds, NULL, NULL, NULL))

さて、あなたの問題に進みましょう。上記のコードからわかるように、select() unblocks のたびに親にシグナルを送っています。これは、マッププロセスごとに複数回発生する可能性があります。map プロセスのいずれかが reduce プロセスにデータを送信するselect()たびに、ループ内の残りのコードをすべてブロック解除して実行することができます。答え半分でも構いません。

すべてを削減した後にシグナルを送信する場合は、すべてのプロセスが完了したことを検出し、ループを終了してから (ループの外側で) 親にシグナルを送るロジックを実装する必要があります。

編集:このようなことを試してください(例をより明確にするために、コードの詳細をいくつか削除しました)。

void reduce() {

    int i, answer, waiting, ret;
    fd_set read_set, selected_set;

    FD_ZERO(&read_set);

    for (i = 0; i < maps_nr; i++)
        FD_SET(fd_maps_to_reduce[i][READ], &read_set); 

    waiting = maps_nr; /* how many answers are we expecting? */

    while(waiting > 0 &&
          selected_set = read_set,
          select(FD_SETSIZE, &selected_set, NULL, NULL, NULL)) {

        for (i = 0; i < maps_nr; i++) {

            if (FD_ISSET(fd_maps_to_reduce[i][READ], &set)) {
                close(fd_maps_to_reduce[i][WRITE]);

                /* read your result. Once you have it: */
                FD_CLR(fd_maps_to_reduce[i][READ], &read_set);
                /* Now you won't wait for that pipe to produce data. */
                waiting--;
            }

        }
    }

    /* Now you are out of the select loop. Signal, or whatever. */

}

編集2:ちなみに、ここではさまざまなプロセスを扱っているため、結果が0になる場合があります。reduce プロセスには独自の結果変数のコピーがあり、メイン プロセスのものは変更されません。あなたはそれをIPCする必要があります。すでにそのためのコードを書いている場合は別のパイプかもしれません。

于 2010-10-16T04:10:23.007 に答える