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

发布于 2024-09-28 09:16:19 字数 1923 浏览 8 评论 0原文

我正在实现一个经典的映射缩减程序,其中我有一个父级,它生成 N 个子级(映射)+ 1(缩减)。父级通过无名管道向 N 个子级中的每一个发送信息。映射处理请求并发送结果(一个 int)以进行归约。 reduce 执行选择并对从映射到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()中被阻塞,并打印全局var结果。

我怎样才能做到这一点?减少有问题吗?

I'm implementing a classical map-reduce program in which I have a parent that spwans N children(maps) + 1(reduce). The parent sends info, through unnamed pipes, to each one of the N children. The maps process the request and send the result, an int, to reduce. The reduce does a select and sums up every counter writen on the pipes from map to reduce.

At the end, reduce has to send a signal SIGUSR1 with the result, but my code does it many times and wrong, because it prints always o in the signal handler. Is part of the code:

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");
    }
}

and in the parent, after creating pipes and children I have something like this:

(...)
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);
}

The problem is that the reduce process sums correctly and prints correctly, but the signal is being send many times and I only want one, i.e., in the wend sends a signal sigusr1 to the parent, which is blocked in pause(), and prints the global var result.

How can I do that? Is something wrong in reduce isn't it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

遗忘曾经 2024-10-05 09:16:19

首先,您可以创建一个更好看的 select() 循环,如下所示:

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

现在,解决您的问题。正如我从上面的代码中看到的,您每次 select() 解锁时都会向父级发出信号,这在每个地图进程中可能会发生多次。每次任何映射进程将数据发送到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 它,如果已经为此编写了代码,也许是另一个管道。

First, you can create a better-looking select() loop like this:

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

Now, on to your problem. As I see from the code above, you're signaling the parent every time select() unblocks, which can happen more than once per map process. select() may unblock and run all the rest of the code in the loop every time any of your map processes sends data to the reduce process. Even if it's half an answer.

If you want to send the signal once you've reduced everything, you have to implement some logic to detect that all processes are done, end the loop, and then (outside the loop) signal the parent.

Edit: try something like this (I removed some details of your code, so as to make the example clearer).

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: and by the way, your result may be printing 0 because you're dealing with different processes here. The reduce process has its own copy of the result variable, it won't change the one on the main process. You have to IPC it, maybe another pipe if already wrote code for that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文