不调用MPI_Comm_create_keyval中提供的回调

不调用MPI_Comm_create_keyval中提供的回调,c,callback,parallel-processing,mpi,hpc,C,Callback,Parallel Processing,Mpi,Hpc,我正在阅读“使用MPI”,并尝试自己执行代码。第6.2章中有一个非阻塞广播代码。我尝试使用自己的回调运行,而不是MPI\u NULL\u COPY\u FN或MPI\u NULL\u DELETE\u FN。这是我的代码,它与书中的代码非常相似,但不会调用回调。我不知道为什么。使用-Wall编译时没有警告或错误。你能帮我吗?非常感谢 #include <stdio.h> #include <stdlib.h> #include <mpi.h> static

我正在阅读“使用MPI”,并尝试自己执行代码。第6.2章中有一个非阻塞广播代码。我尝试使用自己的回调运行,而不是
MPI\u NULL\u COPY\u FN
MPI\u NULL\u DELETE\u FN
。这是我的代码,它与书中的代码非常相似,但不会调用回调。我不知道为什么。使用
-Wall
编译时没有警告或错误。你能帮我吗?非常感谢

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

static int ibcast_keyval=MPI_KEYVAL_INVALID;

typedef struct
{
    MPI_Comm comm;
    int ordering_tag;
} Ibcast_syshandle;

typedef struct
{
    MPI_Request *req_array;
    MPI_Status *stat_array;
    int num_sends;
    int num_recvs;
} Ibcast_handle;

int Ibcast_work(Ibcast_handle *handle)
{
    if(handle->num_recvs==0)
        MPI_Startall(handle->num_sends, handle->req_array);
    else
        MPI_Startall(handle->num_recvs, &(handle->req_array[handle->num_sends]));
    return MPI_SUCCESS;
}

int Ibcast_copy(MPI_Comm oldcomm, int keyval, void *extra, void *attr_in, void *attr_out, int *flag)
{
    Ibcast_syshandle *syshandle=(Ibcast_syshandle *)attr_in;
    Ibcast_syshandle *new_syshandle;
    printf("keyval=%d\n", keyval);
    fflush(stdout);
    if((keyval==MPI_KEYVAL_INVALID)||(keyval!=ibcast_keyval)||(syshandle==NULL))
        return 1;
    new_syshandle=(Ibcast_syshandle *)malloc(sizeof(Ibcast_syshandle));
    new_syshandle->ordering_tag=0;
    MPI_Comm_dup(syshandle->comm, &(new_syshandle->comm));
    {
        int rank;
        MPI_Comm_rank(new_syshandle->comm, &rank);
        printf("Ibcast_copy called from %d\n", rank);
        fflush(stdout);
    }
    *(void **)attr_out=(void *)new_syshandle;
    *flag=1;
    return MPI_SUCCESS;
}

int Ibcast_delete(MPI_Comm comm, int keyval, void *attr_val, void *extra)
{
    Ibcast_syshandle *syshandle=(Ibcast_syshandle *)attr_val;
    {
        int rank;
        MPI_Comm_rank(syshandle->comm, &rank);
        printf("Ibcast_delete called from %d\n", rank);
        fflush(stdout);
    }
    if((keyval==MPI_KEYVAL_INVALID)||(keyval!=ibcast_keyval)||(syshandle==NULL))
        return 1;
    MPI_Comm_free(&(syshandle->comm));
    free(syshandle);
    return MPI_SUCCESS;
}

int Ibcast(void *buf, int count, MPI_Datatype datatype, int root, MPI_Comm comm, Ibcast_handle **handle_out)
{
    Ibcast_syshandle *syshandle;
    Ibcast_handle *handle;
    int flag, mask, relrank;
    int retn, size, rank;
    int req_no=0;

    MPI_Comm_size(comm, &size);
    MPI_Comm_rank(comm, &rank);

    if(size==1)
    {
        (*handle_out)=NULL;
        return MPI_SUCCESS;
    }
    if(ibcast_keyval==MPI_KEYVAL_INVALID)
//      MPI_Keyval_create(MPI_NULL_COPY_FN, MPI_NULL_DELETE_FN, &ibcast_keyval, NULL);
        MPI_Comm_create_keyval(Ibcast_copy, Ibcast_delete, &ibcast_keyval, NULL);
    MPI_Comm_get_attr(comm, ibcast_keyval, (void **)&syshandle, &flag);
    if(flag==0)
    {
        syshandle=(Ibcast_syshandle *)malloc(sizeof(Ibcast_syshandle));
        syshandle->ordering_tag=0;
        MPI_Comm_dup(comm, &(syshandle->comm));
        MPI_Comm_set_attr(comm, ibcast_keyval, (void *)syshandle);
    }
    handle=(Ibcast_handle *)malloc(sizeof(Ibcast_handle));
    handle->num_sends=handle->num_recvs=0;
    mask=0x1;
    relrank=(rank-root+size)%size;
    while((mask&relrank)==0 && mask<size)
    {
        if((relrank|mask)<size)
            ++handle->num_sends;
        mask<<=1;
    }
    if(mask<size)
        ++handle->num_recvs;
    handle->req_array=(MPI_Request *)malloc(sizeof(MPI_Request)*(handle->num_sends+handle->num_recvs));
    handle->stat_array=(MPI_Status *)malloc(sizeof(MPI_Status)*(handle->num_sends+handle->num_recvs));
    mask=0x1;
    relrank=(rank-root+size)%size;
    while((mask&relrank)==0 && mask<size)
    {
        if((relrank|mask)<size)
            MPI_Send_init(buf, count, datatype, ((relrank|mask)+root)%size, syshandle->ordering_tag, syshandle->comm, &(handle->req_array[req_no++]));
        mask<<=1;
    }
    if(mask<size)
        MPI_Recv_init(buf, count, datatype, ((relrank & (~mask))+root)%size, syshandle->ordering_tag, syshandle->comm, &(handle->req_array[req_no++]));
    retn=Ibcast_work(handle);
    ++(syshandle->ordering_tag);
    (*handle_out)=handle;
    return retn;
}

int Ibcast_wait(Ibcast_handle **handle_out)
{
    Ibcast_handle *handle=(*handle_out);
    int retn, i;
    if(handle==NULL)
        return MPI_SUCCESS;
    if(handle->num_recvs!=0)
    {
        MPI_Waitall(handle->num_recvs, &handle->req_array[handle->num_sends], &handle->stat_array[handle->num_sends]);
        MPI_Startall(handle->num_sends, handle->req_array);
    }
    retn=MPI_Waitall(handle->num_sends, handle->req_array, handle->stat_array);
    for(i=0; i<(handle->num_sends+handle->num_recvs);i++)
        MPI_Request_free(&(handle->req_array[i]));
    free(handle->req_array);
    free(handle->stat_array);
    free(handle);
    *handle_out=NULL;
    return retn;
}

int main( int argc, char *argv[] )
{
    int buf1[10], buf2[20];
    int rank, i;
    Ibcast_handle *ibcast_handle_1, *ibcast_handle_2;

    MPI_Init( &argc, &argv );
    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
    if (rank == 0) {
    for (i=0; i<10; i++) buf1[i] = i;
    for (i=0; i<20; i++) buf2[i] = -i;
    }
    Ibcast( buf1, 10, MPI_INT, 0, MPI_COMM_WORLD, &ibcast_handle_1 );
    Ibcast( buf2, 20, MPI_INT, 0, MPI_COMM_WORLD, &ibcast_handle_2 );
    Ibcast_wait( &ibcast_handle_1 );
    Ibcast_wait( &ibcast_handle_2 );
    for (i=0; i<10; i++) {
    if (buf1[i] != i) printf( "buf1[%d] = %d on %d\n", i, buf1[i], rank );
    }
    for (i=0; i<20; i++) {
    if (buf2[i] != -i) printf( "buf2[%d] = %d on %d\n", i, buf2[i], rank );
    }
    MPI_Finalize();
    return 0;
}
#包括
#包括
#包括
静态int-ibcast\u-keyval=MPI\u-keyval\u无效;
类型定义结构
{
MPI_通信;
int-u标签;
}Ibcast_系统句柄;
类型定义结构
{
MPI_请求*请求_数组;
MPI_状态*stat_数组;
int num_发送;
int num_recvs;
}IBU手柄;
内部Ibcast_工作(Ibcast_句柄*句柄)
{
if(handle->num\u recvs==0)
MPI\u Startall(句柄->num\u发送,句柄->请求数组);
其他的
MPI_Startall(handle->num_recvs,&(handle->req_array[handle->num_sends]);
返回MPI_成功;
}
int Ibcast_复制(MPI_Comm oldcomm、int keyval、void*额外、void*属性输入、void*属性输出、int*标志)
{
Ibcast\u syshandle*syshandle=(Ibcast\u syshandle*)attr\u in;
Ibcast_syshandle*新的_syshandle;
printf(“keyval=%d\n”,keyval);
fflush(stdout);
if((keyval==MPI_keyval_INVALID)| |(keyval!=ibcast_keyval)| |(syshandle==NULL))
返回1;
new_syshandle=(Ibcast_syshandle*)malloc(sizeof(Ibcast_syshandle));
新建系统句柄->排序标记=0;
MPI_Comm_dup(syshandle->Comm,&(new_syshandle->Comm));
{
整数秩;
MPI_Comm_rank(新系统句柄->Comm,&rank);
printf(“从%d调用的Ibcast\u副本”,秩);
fflush(stdout);
}
*(void**)attr_out=(void*)新的系统句柄;
*flag=1;
返回MPI_成功;
}
int Ibcast_delete(MPI_Comm Comm,int keyval,void*attr_val,void*extra)
{
Ibcast\u syshandle*syshandle=(Ibcast\u syshandle*)属性值;
{
整数秩;
MPI_Comm_rank(系统句柄->Comm,&rank);
printf(“Ibcast\u delete调用自%d\n”,秩);
fflush(stdout);
}
if((keyval==MPI_keyval_INVALID)| |(keyval!=ibcast_keyval)| |(syshandle==NULL))
返回1;
无MPI通信(&(syshandle->Comm));
自由(系统句柄);
返回MPI_成功;
}
int Ibcast(void*buf,int count,MPI_数据类型数据类型,int root,MPI_Comm Comm,Ibcast_handle**handle_out)
{
Ibcast_syshandle*syshandle;
Ibcast_手柄*手柄;
int标志、掩码、relrank;
整数、大小、等级;
int req_no=0;
MPI_通信大小(通信和大小);
MPI_通信等级(通信和等级);
如果(大小==1)
{
(*handle_out)=空;
返回MPI_成功;
}
如果(ibcast_keyval==MPI_keyval_无效)
//MPI_Keyval_create(MPI_NULL_COPY_FN、MPI_NULL_DELETE_FN和ibcast_Keyval,NULL);
MPI_Comm_create_keyval(Ibcast_copy,Ibcast_delete,&Ibcast_keyval,NULL);
MPI_Comm_get_attr(Comm,ibcast_keyval,(void**)和syshandle,以及flag);
如果(标志==0)
{
syshandle=(Ibcast_syshandle*)malloc(sizeof(Ibcast_syshandle));
syshandle->ordering_tag=0;
MPI_Comm_dup(Comm,&(syshandle->Comm));
MPI_Comm_set_attr(Comm,ibcast_keyval,(void*)系统句柄);
}
handle=(Ibcast_handle*)malloc(sizeof(Ibcast_handle));
handle->num\u sends=handle->num\u recvs=0;
掩码=0x1;
relrank=(秩根+大小)%size;
而((mask&relrank)==0&&masknum_recvs));
handle->stat\u array=(MPI\u Status*)malloc(sizeof(MPI\u Status)*(handle->num\u sends+handle->num\u recvs));
掩码=0x1;
relrank=(秩根+大小)%size;
而((mask&relrank)==0&&maskcomm,&(handle->req_数组[req_no++]);
maskreq_数组[req_no++]);
retn=Ibcast_工作(手柄);
++(系统句柄->订购标签);
(*handle_out)=句柄;
返回retn;
}
int Ibcast\u wait(Ibcast\u句柄**句柄\u out)
{
Ibcast_handle*handle=(*handle_out);
国际网,i;
if(handle==NULL)
返回MPI_成功;
if(handle->num\u recvs!=0)
{
MPI_Waitall(handle->num_recvs,&handle->req_数组[handle->num_sends],&handle->stat_数组[handle->num_sends]);
MPI\u Startall(句柄->num\u发送,句柄->请求数组);
}
retn=MPI_Waitall(句柄->num_发送,句柄->请求数组,句柄->stat_数组);
对于(i=0;inum\u发送+句柄->num\u recvs);i++)
无MPI请求(&(句柄->请求数组[i]);
空闲(句柄->请求数组);
自由(句柄->状态数组);
自由(把手);
*handle_out=NULL;
返回retn;
}
int main(int argc,char*argv[])
{
int buf1[10],buf2[20];
int秩,i;
Ibcast_句柄*Ibcast_句柄_1、*Ibcast_句柄_2;
MPI_Init(&argc,&argv);
MPI通信等级(MPI通信世界和等级);
如果(秩==0){

对于(i=0;i而言,在复制或删除通信器时,或在删除属性时,回调函数用于复制和删除创建的属性。回调函数是必需的,因为属性可以是完全任意的

因此,这里有一个精简版的代码,它确实有效(创建这样的代码是一种有用的方法,既可以跟踪问题,又可以在类似这样的网站上获得帮助):


在代码中,在设置属性之前,在Ibcast中复制通信器,这样就永远不会调用复制回调(因为没有要复制的内容)。您可以通过在dup之前设置属性来修复该部分,但还有另一个问题-您在回调中调用dup并释放,这是错误的;这些函数(间接地)调用回调,而不是反之亦然。

你有解决方案吗?这似乎很复杂。如果我想使用回调,母鸡和蛋的问题。我不确定我是否理解这个问题-你的回调需要做的就是复制和删除属性。不要从回调中调用dup/free,从Ibcast调用它们……这个例子需要一个小的解决方案修复。复制回调的
*标志
参数需要设置为0或1,以指示MPI库是否应将属性复制到
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>

static int ibcast_keyval;

int Ibcast_copy(MPI_Comm oldcomm, int keyval, void *extra, void *attr_in, void *attr_out, int *flag)
{
    printf("In ibcast_copy: keyval = %d\n", keyval);
    *flag = 1;
    return MPI_SUCCESS;
}

int Ibcast_delete(MPI_Comm comm, int keyval, void *attr_val, void *extra)
{
    printf("In ibcast_delete: keyval = %d\n", keyval);
    return MPI_SUCCESS;
}

int main( int argc, char *argv[] )
{
    int rank, i;
    int attr=2;

    MPI_Init( &argc, &argv );
    MPI_Comm_rank( MPI_COMM_WORLD, &rank );

    MPI_Comm duped_comm;

    MPI_Comm_create_keyval(Ibcast_copy, Ibcast_delete, &ibcast_keyval, NULL);
    MPI_Comm_set_attr( MPI_COMM_WORLD, ibcast_keyval, &attr);
    MPI_Comm_dup( MPI_COMM_WORLD, &duped_comm);
    MPI_Comm_free( &duped_comm );
    MPI_Comm_delete_attr( MPI_COMM_WORLD, ibcast_keyval );

    MPI_Finalize();
    return 0;
}
$ mpirun -np 1 ./comm-attr
In ibcast_copy: keyval = 10
In ibcast_delete: keyval = 10
In ibcast_delete: keyval = 10