我有一段MPI C代码,如下所示:
for(i=0;i<NTask;i++)
{
got_initial_bit_of_data[i]=0;
if(need_to_communicate with i)
MPI_ISend(&bit_of_pre_data_for_i,1,MPI_INT,partner,0,MPI_COMM_WORLD,&pre_requests[i]);
}
while(1)
{
MPI_Testsome(NTask,pre_requests,&ndone,idxs,MPI_STATUSES_IGNORE)
if(ndone)
{
for(i=0;i<ndone;i++)
{
MPI_ISend(&the_main_block_of_data_for_i,size_of_block,MPI_BYTE,idxs[i],1,MPI_COMM_WORLD,&main_requests[idxs[i]]);
}
}
//Other stuff that doesn't matter
MPI_IProbe(MPI_ANY_SOURCE,0,MPI_COMM_WORLD,&flag,&status);
if(!flag)
{
MPI_IProbe(MPI_ANY_SOURCE,1,MPI_COMM_WORLD,&flag,&status);
}
if(flag)
{
//Receiving the initial little bit of data
if(status.MPI_TAG==0)
{
//Location 1
got_initial_bit_of_data[status.MPI_SOURCE]=1;
MPI_Recv(&useful_location,1,MPI_INT,status.MPI_SOURCE,MPI_STATUS_IGNORE);
}
//Receiving the main bit of data
else if(status.MPI_TAG==1)
{
//Location 2
if(got_initial_bit_of_data[status.MPI_SOURCE]!=1)
//Something has gone horribly wrong...
//Receive the main bit of data here...
}
}
}
显然,我省略了很多细节,因为完整的代码有几百行长。如果我所做的事情看起来有点奇怪,那可能是因为省略的代码块中的某些内容。
其思想是,在开始时,每个处理器都会向它想与之交谈的处理器发送一条“通知”消息。当它检测到这些处理器已经收到这个消息(即当MPI-Testsome指示“announcement”MPI-Isend完成时),它应该发送一大块数据。
从处理器接收数据的角度来看,它应该首先在位置1接收公告消息,这将导致MPI_Testsome指示Isend已完成并发送大块数据。然后,接收处理器应在位置2接收主数据块。按照这种逻辑,当got_initial_bit_of_data[status.MPI_SOURCE]为0时,应该不可能到达位置2,但这正是偶尔发生的情况,我想知道原因。
要么我把代码的逻辑弄错了,要么就是缺少一些IProbe和Testsome的微妙之处。
我也退出并重新进入整个代码块,不同的处理器在不同的时间点进出,但只有当所有的IsEnter都被处理时(如TestFoice所说的,它们已经完成)。
如果上面的解释没有任何意义,那么我想知道的是,在什么情况下Testsome会声明一个ISend在没有匹配的receive完成(甚至没有开始)的情况下完成?处理器调用IProbe是否足以使Testsome考虑请求已完成?
最佳答案
如果上面的解释没有任何意义,那么我想知道的是,在什么情况下Testsome会声明一个ISend在没有匹配的receive完成(甚至没有开始)的情况下完成?处理器调用IProbe是否足以使Testsome考虑请求已完成?
MPI_Testsome所能保证的是,MPI不再需要从ISend使用的缓冲区。如果要确保收件人已启动接收,请使用同步格式ISSend。