1

我的应用程序与 LAM/MPI 一起工作,但它与 OpenMPI 一起崩溃。

下面是我的代码的外观。

void Comm::nonblocking_send( int s_idx , int e_idx )
{      
      MPI_Wait(&mpireq,&mpistat);


      buffer.clear();

      list<class vertex*>::iterator vit;

      for( vit=our_dag->cur_block_intmeds.begin() ; vit!=our_dag->cur_block_intmeds.end() ; vit++ )
      {
        vertex * v = (*vit);

        list<class edge*> in_edges = v->in_edges;
        list<class edge*>::iterator eit;

        for( eit=in_edges.begin() ; eit!=in_edges.end() ; eit++ )
        {
            int x_idx = (*eit)->src->idx;
            int     y_idx = (*eit)->tgt->idx;
            double  dydx  = (*eit)->partial;

            struct partial * p = new partial();
            //ownership info
            p->rank = our_dag->rank;
            //structural info
            p->x_idx = x_idx;
            p->y_idx = y_idx;
            p->dydx = dydx;
            //block info
            p->block_idx = our_dag->block_idx;
            p->s_idx = s_idx;
            p->e_idx = e_idx;

            buffer.push_back(*p);

            delete p;
        }
      }

      MPI_Isend( &buffer[0] , buffer.size() , MPI_PARTIAL , 0 , DAG_MERG_REQ ,   MPI_COMM_WORLD , &mpireq );    
}

如您所见,在函数开始时,调用 MPI_Wait,然后进行一些计算,最终在函数结束时调用相应的 MPI_ISend。

每次使用 OpenMPI 运行时,我都会从 MPI_Wait 中不断收到分段错误。

我通过检查函数是否是第一次使用布尔变量*first_time*调用来解决此问题,如下所示。

void Comm::nonblocking_send( int s_idx , int e_idx )
    {      
          if(first_time)

               first_time = false;
          else

               MPI_Wait(&mpireq,&mpistat);


          buffer.clear();

          list<class vertex*>::iterator vit;

          for( vit=our_dag->cur_block_intmeds.begin() ; vit!=our_dag->cur_block_intmeds.end() ; vit++ )
          {
            vertex * v = (*vit);

            list<class edge*> in_edges = v->in_edges;
            list<class edge*>::iterator eit;

            for( eit=in_edges.begin() ; eit!=in_edges.end() ; eit++ )
            {
                int x_idx = (*eit)->src->idx;
                int     y_idx = (*eit)->tgt->idx;
                double  dydx  = (*eit)->partial;

                struct partial * p = new partial();
                //ownership info
                p->rank = our_dag->rank;
                //structural info
                p->x_idx = x_idx;
                p->y_idx = y_idx;
                p->dydx = dydx;
                //block info
                p->block_idx = our_dag->block_idx;
                p->s_idx = s_idx;
                p->e_idx = e_idx;

                buffer.push_back(*p);

                delete p;
            }
          }

          MPI_Isend( &buffer[0] , buffer.size() , MPI_PARTIAL , 0 , DAG_MERG_REQ ,   MPI_COMM_WORLD , &mpireq );    
    }

这里有人知道这个错误吗?

干杯。

4

2 回答 2

5

MPI 允许在调用和时使用空请求句柄MPI_REQUEST_NULL(不要与 C/C++NULL指针混淆)。每当向 传递空请求句柄时,调用立即返回空状态,即状态对象的字段设置如下:MPI_WaitMPI_TestMPI_Wait

.MPI_TAG = MPI_ANY_TAG
.MPI_SOURCE = MPI_ANY_SOURCE
.MPI_ERROR = MPI_SUCCESS

无论提供什么数据类型,以空状态调用MPI_Get_countand总是返回 0。MPI_Get_elements每当一个空请求句柄被传递给MPI_Test时,调用立即返回一个空状态并且完成标志设置为true

两者MPI_WaitMPI_Test将已完成操作的请求句柄设置为MPI_REQUEST_NULL. 允许无错误地传递空句柄允许使用相同的句柄变量重复调用任何等待/测试函数而不会产生任何不良影响:

MPI_Isend(..., &req);
// req now contains a handle to the non-blocking send
MPI_Wait(&req, &status);
// The non-blocking send is first completed, then req is set to MPI_REQUEST_NULL
MPI_Wait(&req, &status);
// No-op, returns an empty status

因此,对于这个问题中的情况,只需MPI_REQUEST_NULL在构造函数中设置(初始化)请求变量即可。不需要对函数的第一次调用进行特殊测试,并且代码的第一个版本将按预期工作。

于 2014-04-08T08:34:17.980 回答
1

正如 suszterpatt 在评论中暗示的那样,MPI_Wait使用未初始化的调用request是未定义的,它出现段错误并不一定令人惊讶。使用未初始化的请求并不等同于无操作。未初始化的结构包含指针(例如,在 LAM/MPI 中,MPI_Request 类型实际上本身就是一个指向结构的指针),如果它没有被初始化,很可能你会得到一个段错误。

如果您想要与无操作等效的东西,则可以使用MPI_Waitall计数为 0;

void Comm::nonblocking_send( int s_idx , int e_idx )
{     
      if (first_time) count = 0; 
      MPI_Waitall(count, &mpireq,&mpistat);

      /* ... */
      count = 1;
      first_time = false;
      /* ... */

}
于 2012-01-07T16:05:22.167 回答