如何解决通过包装器传递指向MPI_Win_allocate_shared的指针
我很难理解指针传递的结果:
我有以下基本程序
#include <mpi.h>
void ALLOC_SHM(double * arr,int sz);
void MPI_WRAP( MPI_Aint size,int disp,MPI_Comm comm,double * bufptr,MPI_Win* win ) ;
int main(int argc,char const *argv[])
{
int size,whoami;
double* arr;
MPI_Init(NULL,NULL) ;
MPI_Comm_size( MPI_COMM_WORLD,&size );
MPI_Comm_rank(MPI_COMM_WORLD,&whoami);
ALLOC_SHM(arr,1000);
return 0;
}
void ALLOC_SHM(double * arr,int sz)
{
MPI_Win win;
MPI_Aint size = sz*sizeof(double);
int disp = sizeof(double);
printf("in alloc before mpi_wrap: %p\n",arr);
MPI_WRAP(size,disp,MPI_COMM_WORLD,arr,&win);
printf("in alloc AFTER mpi_wrap: %p\n",arr);
return;
}
void MPI_WRAP( MPI_Aint size,MPI_Win* win )
{
printf("in mpi_wrap before WIN_ALLOC: %p\n",bufptr);
int ierr = MPI_Win_allocate_shared( size,MPI_INFO_NULL,comm,&bufptr,win );
printf("in mpi_wrap AFTER WIN_ALLOC: %p\n",bufptr);
return;
}
我的疑问:
-
对MPI_WRAP的调用是错误的,但是为什么呢?是因为MPI Api需要指向指针的地址(即
**arr
) -
如果上述原因正确,则可以通过将地址传递给指针来解决,因此我的CALL为
MPI_WRAP(size,&arr,&win);
-
现在,如果这是正确的(2),我意外地意识到,在不更改我的
MPI_WRAP
接口的同时,我的代码在运行它时没有问题。但是很明显,我没有传递指针(*bufptr
),而是传递了**buftr
。然后,我将MPI_WRAP
接口更改为以下MPI_WRAP( MPI_Aint size,double ** bufptr,MPI_Win* win )
(我将其更改为双指针,并且仍然按照(2)中的操作调用它)。确实,这确实令人惊讶。我与MPI一起工作了很长时间,才知道仅仅因为它现在可以工作,并不意味着它是对的-而且您很幸运它可以针对您的情况进行工作-因此,这里发生了什么,我怎么能同时考虑这两个接口和他们俩似乎都起作用?
解决方法
一些MPI标准的阅读和对C ++指针和函数参数的理解可能会在这里有所帮助。例如,阅读MPI_Win_allocate_shared
的Open MPI手册页:
在每个进程上,它分配至少 size 个字节的内存,这些内存在 comm 中的所有进程之间共享,并且返回一个指向本地分配的段的指针在 baseptr 中,可用于在调用过程中加载/存储访问。
C ++函数通过函数参数返回值的唯一方法是,如果该参数是值的引用或指向该值的位置的指针。因此,尽管手册页将baseptr
列为void *
,但实际上它的类型为void **
。
现在,两者之间的区别:
void foo(void *bar) {
MPI_Win_allocate_shared(...,&bar,...);
}
void *baz;
foo(baz);
和
void foo(void **bar) {
MPI_Win_allocate_shared(...,bar,...);
}
void *baz;
foo(&baz);
尽管在两种情况下,对MPI_Win_allocate_shared
的调用最终都以void **
作为参数,但前一种情况在概念上是错误的。您不是传递baz
的地址,而是传递指向形参bar
的指针,该形参持有baz
值的副本。形式参数的语义基本上是使用实际函数参数初始化的局部变量的语义:
void *bar = baz;
MPI_Win_allocate_shared(...,...);
这会将新值写入bar
,同时保持baz
的值不变。这就是为什么在MPI_Win_allocate_shared
内的MPI_WRAP
调用之后看到一个新值,但是一旦返回到调用函数,就会看到一个旧值的原因。
后者类似于
void **bar = &baz;
MPI_Win_allocate_shared(...,...);
这具有完全不同的语义。 bar
现在包含baz
的地址,这就是位置MPI_Win_allocate_shared
将分配的缓冲区的地址写入其中。
所以正确的C / C ++代码是:
void foo(void **bar) {
MPI_Win_allocate_shared(...,...);
}
void *baz;
foo(&baz);
C ++具有引用,并且可以这样编写:
void foo(void *&bar) {
MPI_Win_allocate_shared(...,...);
}
void *baz;
foo(baz);
这与第一种(不正确的)情况非常相似,主要区别在于,这里的形式参数bar
是实际参数baz
的别名,所以现在&bar
是与&baz
相同。因此,MPI_Win_allocate_shared
会将返回值写入baz
的存储空间。
附注:我推荐Open MPI的手册页,因为其中的解释基本上是MPI标准的摘录。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。