在固定时间后停止所有MPI进程

时间:2017-03-27 17:12:34

标签: c mpi

我面临着一种特殊的情况。

我有一个MPI程序,可以创建16个MPI进程 mpirun -np 16 a.out

现在我希望所有这16个进程运行一段固定时间,比如60秒,之后他们都应该将结果报告给一个公共进程(比如排名为0的进程)。

所以我将在60秒后从0级进行收集。现在,我如何确保所有进程在60秒后停止?

伪代码:

/*All processes (except 0) are doing the following:*/
while (1) {
  MPI_Send (to process 0)
  MPI_Recv (from process 0)
}

/*Process 0 roughly does the following:*/
while(1) {
  MPI_Recv (from any other process)
  Process the request
  MPI_Send (back to clients)
}

/* After 60 seconds, stop all processes and gather results at Process 0. */
1. Catch a SIGALRM signal after 60 secs.
2. Do dummy MPI_Irecv(any source) to ensure that it any client blocking on MPI_Send() is woken up.
3. Now do an MPI_Send to all clients with a special value in buffer telling them to terminate.
4. MPI_gather from all clients.

进程0的作用类似于服务器,其余的是客户端。

我尝试使用信号处理(SIGALRM),但文档说使用MPI信号处理是不安全的。

如果无法使用信号,那么我们该如何处理?

2 个答案:

答案 0 :(得分:1)

我相信Leslie Lamport证明了分布式系统没有绝对的时间。类似于狭义相对论,每个过程从其自身的角度来看具有相对时间。也就是说,如果你想在程序启动后大约60秒停止(从外部观察者的角度来看),只有一个进程应该监视时钟并决定停止。

考虑到你所说的,过程0似乎是理想的候选者。既然你不能使用SIGALARM(我不认为任何其他异步方法真的适合像你这样的紧密同步的MPI应用程序),我的建议是在你的进程0 MPI_Recv之后立即检查系统时间。现在减去时间与流程开始的时间,如果它大于60,则通过MPI_Send将0信号发送到所有其他流程停止。

编辑:现在我明白过程0单独响应每个请求,程序应该有点不同。

在进程0的每个MPI_Recv之后,检查自执行开始以来是否已经过了60秒。如果有,请响应当前客户端进程退出,然后退出循环,并执行以下操作:

for(int i = 2; i < 16; ++i) {
    MPI_Status s;
    MPI_Recv(buf, count, datatype, MPI_ANY, tag, comm, &s);

    MPI_Send(message_to_quit, count, datatype, s.MPI_SOURCE, tag, comm);
}

这样,进程0将等待,并在自行退出之前发出其他每个进程的信号。

答案 1 :(得分:0)

Ivella给出的建议有效。除了我必须做一个更改。

在流程0中:

60秒到期后(使用gettimeofday计算) 打破while循环并执行以下操作:

  1. 进入另一个循环约5秒,其中进程0将使用MPI_Iprobe继续探测是否有任何客户端正在等待MPI_Send。

  2. 如果MPI_Iprobe将标志设置为true,则从进程0发出MPI_Recv以确保所有客户端现在都来自MPI_Send并且正在等待MPI_Recv上的响应。

  3. 此时,向每个宣布终止的客户发送一个特殊字符。

  4. 现在所有进程执行MPI_Reduce,目标设置为进程0,之后它们都终止。

  5. 60秒到期后的伪代码:

    timeout = 5 secs
    
    while (time < timeout) {
    
       MPI_Iprobe(any_source, flag,...)
    
       /*this is to ensure that all waiting clients are unblocked from MPI_Send*/
       if (flag != 0) {
           MPI_Recv(status.MPI_SOURCE);
       }
    }
    

    现在, 向所有宣布终止的客户发出MPI_Send,然后发出MPI_Reduce(或收集)并退出。