如何使用MPI终止Signal

时间:2018-04-26 21:52:01

标签: c mpi

这是我在c中用MPI编写的第一个程序,该程序应该在15秒内终止,但事实并非如此。它甚至没有通过if(end_now == 1)语句。有谁知道这里发生了什么?代码简化如下:

int end_now = 0;


void sig_handler(int signo)
{
    if (signo == SIGUSR1) {
        end_now = 1;
        printf ( "  %8d  %8d\n", current_number, current_total);
    }
}

int main ( int argc, char **argv ){
   int id;
   int count;

   MPI_Init (&argc, &argv);
   MPI_Comm_size (MPI_COMM_WORLD, &count);
   MPI_Comm_rank (MPI_COMM_WORLD, &id);

   signal(SIGUSR1, sig_handler);


   while (1){
       //MPI_Allreduce is called here to sum up the subtotal calculated by child processes
        if (end_now == 1){
            printf("here\n");  //this "here is never printed out"
            break;
        }
    }
    MPI_Finalize ();
    return 0;
}

我正在使用超时--signal = USR1 15 mpirun.openmpi -np 2 ./a.out来执行我的Mac上的代码。 感谢任何可能提供帮助的人。

4 个答案:

答案 0 :(得分:1)

您正在向mpirun发送信号,而不是您的可执行文件。由于mpirun本身没有SIGUSR1处理程序,因此没有任何反应。

BTW,使用MPI程序的信号不是你想要做的事情。 MPI程序依赖于以锁步方式运行的多个调用,这与信号的异步和每个进程性质不匹配。

答案 1 :(得分:1)

Sneftel是对的。 Gilles Gouaillardet也很对。我想补充一些其他信息。

即使您将信号发送到实际程序而不是“mpirun”,那么您可能只将其发送到您的进程的ONE而不是所有进程。

是的,在MPI计划中,信号是不正确的。但即使你想使用它们,你也应该首先调试获得它们的任何进程以及它们中的哪些进程。

将“printf”直接插入信号处理程序。打印类似“MPI进程号%d得到信号”并将MPI_COMM_RANK插入此printf。(UPD 2018-04-27 7:31 MSK:对不起,我没注意到你已经有{{1}在你的代码中。)(注意:我认为MPI程序中的“printf”只允许在第一个进程中使用,并且在其他进程中使用“printf”可能是个坏主意,但是出于调试的目的,我会认为是“printf”。 “直接来自信号处理程序是个坏主意,但是,再次,出于调试目的,将继续。”

您将确定您的流程是否获得信号以及哪些信号。

如果您对结果不满意,请尝试使用不同的程序而不是gtimeout。例如,GNU Coreutils的“超时”。 (嗯,这是Mac,我不确定,GNU Coreutils可以在Mac上使用,但我仍然认为你可以找到一些“超时”。)

然后:你没有描述你的设置。您的MPI程序是在不同的主机上还是在一台主机上运行? MPI“程序”真的是作为单独的程序还是作为线程实现的?您使用哪种MPI实现以及哪个版本?如果您不知道MPI如何启动您的流程,至少要说明我们,您如何安装MPI实现以及如何配置它。

甚至你可以在没有任何“超时”或“gtimeout”的情况下完成任务。只需在一个控制台中输入:

printf

这将在将其PID存储到〜/ pid-of-mpirun时运行“mpirun”。并在另一个终端中并行运行(当然,您不需要在同一时刻完全运行此命令):

sh -c 'echo $$ > ~/pid-of-mpirun; exec ~/opt/usr/local/bin/mpirun -np 2 ./a.out'

这需要15秒并发送USR1来处理哪个PID在〜/ pid-of-mpirun中。

但所有这些可能会将USR1发送到“mpirun”而不是实际进程(我不确定,测试一下!)。如何发送到实际流程?那么,您可以阅读“kill”的手册页,并尝试了解如何向整个流程组发送信号,而不是仅仅针对一个流程。

此外,您可以直接在C程序中将PID写入某个文件。

示例:

sleep 15; kill -USR1 $(cat ~/pid-of-mpirun)

当然,您应该以某种方式确保在不同的进程中创建不同的文件。例如,从MPI_COMM_RANK生成文件名。

答案 2 :(得分:0)

end_now也应声明为volatile,否则编译器可能会优化将永远运行的主循环。

答案 3 :(得分:0)

我建议不要在信号处理程序中使用printf,因为printf是不可重入的函数,在某些平台上这可能导致程序崩溃。