我正在实现一个经典的映射缩减程序,其中我有一个父级,它生成 N 个子级(映射)+ 1(缩减)。父级通过无名管道向 N 个子级中的每一个发送信息。映射处理请求并发送结果(一个 int)以进行归约。 reduce 执行选择并对从 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);
}
问题是reduce进程正确地求和并正确地打印,但是信号被发送了很多次,而我只想要一个,即,在wend中向父进程发送一个信号sigusr1,该信号在pause()中被阻止,并打印全局变量结果。
我怎样才能做到这一点?是不是reduce出了什么问题?
最佳答案
首先,您可以创建一个更好看的 select() 循环,如下所示:
while (newfds = readfds, select(n, &newfds, NULL, NULL, NULL))
现在,解决你的问题。正如我从上面的代码中看到的,您每次 select() 解锁时都会向父级发出信号,这在每个 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 它,如果已经为此编写了代码,也许是另一个管道。
关于c - select()中的问题并最终发送信号SIGUSR1(C语言),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3947615/