проблемы в select () и отправке сигнала SIGUSR1 в конце (язык C) - PullRequest
0 голосов
/ 16 октября 2010

Я реализую классическую программу сокращения карт, в которой у меня есть родитель, который включает в себя N детей (карты) + 1 (уменьшение). Родитель отправляет информацию через неназванные каналы каждому из N дочерних элементов. Карты обрабатывают запрос и отправляют результат, int, для уменьшения. Редакция делает выборку и суммирует каждый счетчик, записанный на каналах с карты, чтобы уменьшить.

В конце редуктор должен отправить сигнал 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);
}

Проблема в том, что процесс приведения правильно суммирует и печатает правильно, но сигнал отправляется много раз, а мне нужен только один, т.е. в wend отправляет сигнал sigusr1 родителю, который блокируется в pause () и печатает результат глобальной переменной.

Как я могу это сделать? Что-то не так в уменьшении, не так ли?

1 Ответ

1 голос
/ 16 октября 2010

Во-первых, вы можете создать более привлекательный цикл выбора () следующим образом:

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

Теперь к вашей проблеме. Как видно из приведенного выше кода, вы сообщаете родителю каждый раз, когда select () разблокирует , что может происходить более одного раза за процесс карты. 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. */

}

edit 2: и, кстати, ваш результат может быть напечатан 0, потому что вы имеете дело с различными процессами здесь. Процесс сокращения имеет свою собственную копию переменной результата, она не изменит копию в основном процессе. Вы должны IPC это, может быть, другой канал, если уже написал код для этого.

...