0

如何从 MPI 中的单个线程访问全局向量?

我正在使用一个名为 CVODE( SUNDIALS的一部分)的库——特别是 ODE 求解器库。该库与 MPI 一起使用,因此多个线程并行运行。他们都在运行相同的代码。每个线程向它“旁边”的线程发送一条数据。但我希望其中一个线程(rank=0)在某些点打印出数据的状态。

库包含函数,以便每个线程都可以访问自己的数据(本地向量)。但是没有办法访问全局向量。

我需要在特定时间输出所有方程的值。为此,我需要访问全局向量。任何人都知道如何获取 MPI 向量中的所有数据(如果可能,使用 CVODE)?

例如,这是我每个线程运行的代码

  for (iout=1, tout=T1; iout <= NOUT; iout++, tout += DTOUT) {
    flag = CVode(cvode_mem, tout, u, &t, CV_NORMAL);
    if(check_flag(&flag, "CVode", 1, my_pe)) break;
    if (my_pe == 0) PrintData(t, u);
  }
...
static void PrintData(realtype t, N_Vector u) {
   I want to print data from all threads in here
}

在函数(我正在解决的函数)中,我使用andf来回传递数据。但我不能在 PrintData 中真正做到这一点,因为其他进程已经提前运行。另外,我不想增加消息传递开销。我想访问 中的全局向量,然后打印出需要的内容。是否可以?MPI_SendMPI_RecvPrintData

编辑:在等待更好的答案时,我对每个线程进行了编程,将数据传递回第 0 个线程。我不认为这会增加太多的消息传递开销,但如果有更好的方法,我仍然想听听专家的意见(我相信没有更糟糕的方法!:D)。

编辑 2:虽然 angainor 的解决方案肯定是优越的,但我坚持使用我创建的解决方案。为了将来有相同问题的任何人参考,以下是我如何做到的基础知识:

/* Is called by all threads */
static void PrintData(realtype t, N_Vector u, UserData data) {

... declarations and such ...

  for (n=1; n<=my_length; n++) {
    mass_num = my_base + n;
    z[mass_num - 1] = udata[n-1];
    z[mass_num - 1 + N] = udata[n - 1 + my_length];
  }

  if (my_pe != 0) {
    MPI_Send(&z, 2*N, PVEC_REAL_MPI_TYPE, 0, my_pe, comm);

  } else {

    for (i=1; i<npes; i++) {
      MPI_Recv(&z1, 2*N, PVEC_REAL_MPI_TYPE, i, i, comm, &status);
      for (n=0; n<2*N; n++)
        z[n] = z[n] + z1[n];
    }

... now I can print it out however I like...

  return;
}
4

1 回答 1

4

使用 MPI 时,各个线程无法访问“全局”向量。它们不是线程,它们是可以在不同物理计算机上运行的进程,因此不能直接访问全局数据

要执行您想要的操作,您可以将向量发送到 MPI 进程之一(您已这样做)并在那里打印它,或者按顺序打印本地工作部件。使用这样的函数:

void MPI_write_ivector(int thrid, int nthr, int vec_dim, int *v)
{
  int i, j;
  int curthr = 0;

  MPI_Barrier(MPI_COMM_WORLD);
  while(curthr!=nthr){
    if(curthr==thrid){
      printf("thread %i writing\n", thrid);
      for(i=0; i<vec_dim; i++) printf("%d\n", v[i]);
      fflush(stdout);
      curthr++;
      MPI_Bcast(&curthr, 1, MPI_INT, thrid, MPI_COMM_WORLD);
    } else {
      MPI_Bcast(&curthr, 1, MPI_INT, curthr, MPI_COMM_WORLD);
    }
  }
}

所有 MPI 进程都应该同时调用它,因为里面有一个屏障和广播。本质上,该过程确保所有 MPI 进程按顺序打印它们的向量部分,从等级 0 开始。数据不会混乱,因为在任何给定时间只有一个进程写入。

在上面的示例中,使用了广播,因为它在线程打印其结果的顺序上提供了更大的灵活性——当前输出的线程可以决定下一个是谁。你也可以跳过广播,只使用屏障

void MPI_write_ivector(int thrid, int nthr, int vec_dim, int *v)
{
  int i, j;
  int curthr = 0;

  while(curthr!=nthr){
    if(curthr==thrid){
      printf("thread %i writing\n", thrid);
      for(i=0; i<vec_dim; i++) printf("%d\n", v[i]);
      fflush(stdout);
    }
    MPI_Barrier(MPI_COMM_WORLD);
    curthr++;
  }
}
于 2012-09-04T06:55:16.573 回答