这是我在C中使用MPI编写的第一个程序,该程序应该在15秒内终止,但事实并非如此。它甚至没有通过IF(end_now == 1(语句。有人知道这里发生了什么吗?该代码如下所示:
int end_now = 0;
void sig_handler(int signo)
{
if (signo == SIGUSR1) {
end_now = 1;
printf ( " %8d %8dn", 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("heren"); //this "here is never printed out"
break;
}
}
MPI_Finalize ();
return 0;
}
我正在使用timeout -signal = usr1 15 mpirun.openmpi -np 2 ./a.out在我的Mac上执行代码。感谢任何人可能会有所帮助。
您将信号发送给mpirun
,而不是可执行文件。由于mpirun
本身没有SIGUSR1
处理程序,因此什么也不会发生。
顺便说一句,使用MPI程序的信号不是您想做的。MPI程序依赖于在锁定中运行的多个调用,这与信号的异步性和程序性质不符。
sneftel是正确的。Gilles Gouaillardet也很正确。我想添加其他一些信息。
即使您将信号发送到实际程序而不是" Mpirun",也可能将其发送到您的一个流程中,而不是将其发送给所有程序。
是的,在MPI程序中,信号是不对的。但是,即使您想使用它们,您也应该首先调试任何程序以及谁获得它们。
直接将" printf"插入信号处理程序中。打印诸如" MPI Process%d获得信号"之类的东西,然后将MPI_COMM_RANK插入此printf。(UPD 2018-04-27 7:31 MSK:对不起,我没有注意到您已经在您的中有这样的printf
((注意:我认为仅在第一个过程中允许的MPI程序中的" printf",而在其他过程中使用" printf"可能是坏主意,但是出于调试目的而言,我认为直接从信号中使用" printf"处理程序是个坏主意,但同样,出于调试的目的,将会进行。(
您将确定您的流程是否获得信号以及其中的信号。
如果您对结果不满意,请尝试不同的程序而不是GTIMEOUT。例如,GNU Coreutils的"超时"。(嗯,这是Mac,我不确定,GNU Coreutils是否可用Mac,但我仍然认为您可以找到一些"超时"。(
然后:您没有描述您的设置。您的MPI程序是否在不同的主机上运行?MPI"程序"是否真的作为单独的程序或线程实现?您使用哪个MPI实现以及哪个版本?如果您不知道MPI如何启动您的流程,至少说我们,您如何安装MPI实现以及如何配置。
,甚至您都无需任何"超时"或" gtimeout"。只需在一个控制台中输入此内容:
sh -c 'echo $$ > ~/pid-of-mpirun; exec ~/opt/usr/local/bin/mpirun -np 2 ./a.out'
这将运行" Mpirun",同时将其PID存储到〜/PID-MPIRUN中。并在另一个终端并行运行(当然,您不需要在同一时刻完全运行此命令(:
sleep 15; kill -USR1 $(cat ~/pid-of-mpirun)
这将需要15秒,然后发送USR1处理哪个PID在〜/pid-mpirun中。
,但所有这些都可能将USR1发送到" Mpirun",而不是将其发送到实际过程(我不确定,测试此!(。如何发送到实际流程?好吧,您可以阅读"杀死"的手册页面,并尝试了解如何将信号发送给整个过程组而不只是一个过程。
另外,您可以将PID直接写入C程序中的某些文件。
示例:
#include <stdio.h>
#include <unistd.h> // Mac is one of UNIX systems, so we have unistd.h
// ...
FILE *fout = fopen("~/my-pid", "w"); fprintf(fout, "%dn", getpid); fclose(fout);
当然,您应该以某种方式确保在不同的过程中创建不同的文件。例如,从mpi_comm_rank生成文件名。
end_now
也应声明为volatile
,否则编译器可能会优化将永远运行的主循环。
我推荐在信号处理程序中不使用printf,因为printf不可重新输入功能,这可能会导致某些平台上的程序崩溃。