c - select()中的问题并最终发送信号SIGUSR1(C语言)

标签 c signals parent-child select-function

我正在实现一个经典的映射缩减程序,其中我有一个父级,它生成 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/

相关文章:

使用 Axis2/C 连接到需要用户名、密码和 .cer 文件的 Web 服务

python - 在python中,调用后是否有可能发生异常,但其后的try block 为 "before"?

c - 如果事件未决,Linux 上的 pselect() 不会传递信号

javascript - Angular 路由器不选择子状态(嵌套状态)

c - 如何使用 sscanf 检索包含空格的字符串

使用 Unix 系统调用进行 I/O 的 C 程序

android - 强制 View 至少占据其父级高度的一定百分比

javascript - React : Changed state in Child component. 如何查看父组件的变化?

c++ - 函数不再内联。有什么解释吗?

c++ - Linux 编程接口(interface)中的信号处理程序示例