c - 是否可以附加一个回调以在请求完成时执行?

标签 c asynchronous callback request mpi

在 MPI 中,可以运行异步消息传递例程(例如接收,使用 MPI_Irecv)。 是否可以附加一个回调函数,以便在请求完成后立即执行?例如处理接收到的数据。

这是我正在寻找的示例:

#include "mpi.h"
#include <stdio.h>

void mycallback(void* data){
   (int*)data += 1; // add one to the received data
}

int main(int argc, char *argv[]){
    int myid, numprocs, left, right;
    int buffer[10], buffer2[10];
    MPI_Request request;
    MPI_Status status;

    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);

    right = (myid + 1) % numprocs;
    left = myid - 1;
    if (left < 0)
        left = numprocs - 1;

    MPI_Irecv(buffer, 10, MPI_INT, left, 123, MPI_COMM_WORLD, &request);
 // Attach_Callback(request, &mycallback); //somewhere after this point recv is completed an f is executed
    MPI_Send(buffer2, 10, MPI_INT, right, 123, MPI_COMM_WORLD);
    MPI_Wait(&request, &status); //the recv and the callback must have been called at this point
    MPI_Finalize();
    return 0;
}

我发现有一个 MPI_Grequest_startMPI_Grequest_complete 函数,但它们似乎用于其他用途,因为创建的请求与特定消息传递无关。

也许我必须实现一个 Grequest(通用请求),其中回调包含在 MPI_Recv(而不是 MPI_Irecv)中。是这个主意吗?

最佳答案

标准中没有这样的东西。

正如@AhmedMasud 所说,您可以找到一种使用通用请求的方法: http://mpi-forum.org/docs/mpi-3.1/mpi31-report/node297.htm#Node297

正如您在其中读到的那样,由于我同意的某些原因(MPI 线程和您的程序线程之间的工作拆分),该标准可能永远不会包含 Irecv 的回调。

您尝试做的事情并非微不足道,并且与很多可移植性问题有关。您应该问自己的问题:在 MPI 线程中执行回调真的会给我带来任何好处吗?我怀疑您认为这种好处是效率,但是出于效率原因,应该避免使用 Irecv 和 Isend,非阻塞是一个不错的功能,但应该仅在您没有其他选择(例如输出服务器,其中您肯定不想浪费计算客户端的时间(但即便如此,缓冲发送通常会更好,并且会带来更大的带宽和更小的延迟)。

您需要的通信的真正结构是什么? 如果它是 0->1, 1->2 ... n-1->n, n->0 此代码运行良好(并且比您的解决方案更快)那么您可以使用您喜欢的方式轻松定义回调这样做(解决问题的时间会更短,调试更容易 :-)):

template<class Type> 
void Parallel::sendUp(Type& bufferSend,
                      Type& bufferRec, 
                      long len)
{
    if(this->rank()%2==0)
    {
        if(this->rank()!=this->size()-1)
        {
            this->send(bufferSend,len,this->rank());
        }
        if(this->rank()!= 0)
        {
            this->receive(bufferRec,len,this->rank()-1);
        }
        else if(this->size()%2==0)
        {
            this->receive(bufferRec,len,this->size()-1);
        }
    }
    else
    {
        this->receive( bufferRec, len , this->rank()-1);
        if(this->grid_rank()!=this->grid_size()-1)
        {
            this->send(bufferSend,len,this->rank()+1);
        }
        else
        {
            this->send( bufferSend, len , 0);
        }
    }

    if(this->size()%2!=0)
    {
        if(this->rank()==this->size()-1)
        {
            this->send( bufferSend, len , 0);
        }
        if(this->grid()==0)
        {
            this->receive(bufferRec, len , this->size()-1);
        }
    }
}

在该代码中,并行对象“只是”一些 MPI 调用的包装器,只是为了简化调用:

parallel.rank() = rank in the comm
parallel.size() = size of the comm
parallel.send/rec() is defined as follow

template<class Type> 
void Parallel::send(Type* array, int len, int to)
{
    MPI_Send(array, len*sizeof(Type), MPI_BYTE, to, 0,comm_);
}

template<class Type> 
void Parallel::rec(Type* array, int len, int to)
{
    MPI_Send(array, len*sizeof(Type), MPI_BYTE, to, 0,comm_);
}

template<class Type>
MPI_Status Parallel2d::receive(Type& array, int from, int len)
{
    MPI_Status  status;
    MPI_Recv( &array, len*sizeof(Type), MPI_BYTE, from, 0,comm_,&status);
    return status;
}

希望对您有所帮助。

关于c - 是否可以附加一个回调以在请求完成时执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49763675/

相关文章:

c# - 'async' 调用图中的最后一次调用是否需要同步?

javascript - 当你可以在 Javascript 中全局调用函数时,为什么要使用回调呢?

javascript - Promise.promisify 不是函数

callback - PayPal MECL 重定向失败并返回回调

Swift:在 viewDidLoad() 和回调中运行单例函数,不会得到相同的结果

c - scanf() 中的错误

c - 如何按字母顺序对句子中的每个单词进行排序?

c - SSE加载和添加

c - 为什么在 gcc 上接受 const 限定变量作为初始值设定项?

c# - 异步 TCP 服务器(Windows 服务)中的内存泄漏