Проблемы в select() и отправке сигнала SIGUSR1 в конце (язык C)
Я реализую классическую программу сокращения карт, в которой у меня есть родитель, который включает в себя 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 ответ
Во-первых, вы можете создать более привлекательный цикл select() следующим образом:
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. */
}
изменить 2: и, кстати, ваш результат может быть печать 0, потому что вы имеете дело с различными процессами здесь. Процесс сокращения имеет свою собственную копию переменной результата, она не изменит копию в основном процессе. Вы должны IPC это, может быть, другой канал, если уже написал код для этого.