通过包装器传递指向 MPI_Win_allocate_shared 的指针
Passing a pointer to MPI_Win_allocate_shared through a wrapper
我很难理解我的指针传递是怎么回事:
我有以下最小程序
#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, int disp, MPI_Comm comm, double * bufptr, MPI_Win* win )
{
printf("in mpi_wrap before WIN_ALLOC: %p\n", bufptr);
int ierr = MPI_Win_allocate_shared( size, disp, 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, disp,MPI_COMM_WORLD, &arr, &win);
现在如果那是正确的 (2),我无意中意识到我的代码没有问题 运行 它同时没有更改我的 MPI_WRAP
界面。但很明显,我传递的不是指针 (*bufptr
),而是 **buftr
。然后,我将 MPI_WRAP
接口更改为以下 MPI_WRAP( MPI_Aint size, int disp, MPI_Comm comm, double ** bufptr, MPI_Win* win )
(我正在将其更改为双指针,并且仍然按照 (2) 中的方式调用它)。令人惊讶的是,这也奏效了。我已经与 MPI 合作了足够长的时间,知道仅仅因为它现在可以工作,并不意味着它是正确的 - 你很幸运它适用于你的情况 - 因此,这里发生了什么,我怎么能同时考虑接口和它们似乎都有效?
阅读 MPI 标准和了解 C++ 指针和函数参数可能会有所帮助。例如,阅读 MPI_Win_allocate_shared
:
的 Open MPI 手册页
On each process, it allocates memory of at least size bytes that is shared among all processes in comm, and returns a pointer to the locally allocated segment in baseptr that can be used for load/store accesses on the calling process.
C++ 函数通过函数参数 return 值的唯一方法是该参数是引用还是指向值位置的指针。因此,虽然手册页将 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
值的 copy .形式参数的语义基本上是用实际函数参数初始化的局部变量的语义:
void *bar = baz;
MPI_Win_allocate_shared(..., &bar, ...);
这会将一个新值写入 bar
,同时保持 baz
的值不变。这就是为什么在 MPI_WRAP
中调用 MPI_Win_allocate_shared
后你会看到一个新值,但一旦它 return 到调用函数就会看到旧值。
后者类似于
void **bar = &baz;
MPI_Win_allocate_shared(..., bar, ...);
这具有完全不同的语义。 bar
现在包含 baz
的地址,这就是 MPI_Win_allocate_shared
将分配的缓冲区地址写入的位置。
所以正确的C/C++代码是:
void foo(void **bar) {
MPI_Win_allocate_shared(..., bar, ...);
}
void *baz;
foo(&baz);
C++有引用,同样可以这样写:
void foo(void *&bar) {
MPI_Win_allocate_shared(..., &bar, ...);
}
void *baz;
foo(baz);
这与第一个(不正确的)情况非常相似,关键区别在于这里的形式参数 bar
是实际参数 baz
的别名,所以现在 &bar
与 &baz
相同。因此,MPI_Win_allocate_shared
会将 return 值写入 baz
的存储区 space。
旁注:我推荐 Open MPI 的手册页,因为那里的解释基本上是 MPI 标准的摘录。
我很难理解我的指针传递是怎么回事:
我有以下最小程序
#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, int disp, MPI_Comm comm, double * bufptr, MPI_Win* win )
{
printf("in mpi_wrap before WIN_ALLOC: %p\n", bufptr);
int ierr = MPI_Win_allocate_shared( size, disp, 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, disp,MPI_COMM_WORLD, &arr, &win);
现在如果那是正确的 (2),我无意中意识到我的代码没有问题 运行 它同时没有更改我的
MPI_WRAP
界面。但很明显,我传递的不是指针 (*bufptr
),而是**buftr
。然后,我将MPI_WRAP
接口更改为以下MPI_WRAP( MPI_Aint size, int disp, MPI_Comm comm, double ** bufptr, MPI_Win* win )
(我正在将其更改为双指针,并且仍然按照 (2) 中的方式调用它)。令人惊讶的是,这也奏效了。我已经与 MPI 合作了足够长的时间,知道仅仅因为它现在可以工作,并不意味着它是正确的 - 你很幸运它适用于你的情况 - 因此,这里发生了什么,我怎么能同时考虑接口和它们似乎都有效?
阅读 MPI 标准和了解 C++ 指针和函数参数可能会有所帮助。例如,阅读 MPI_Win_allocate_shared
:
On each process, it allocates memory of at least size bytes that is shared among all processes in comm, and returns a pointer to the locally allocated segment in baseptr that can be used for load/store accesses on the calling process.
C++ 函数通过函数参数 return 值的唯一方法是该参数是引用还是指向值位置的指针。因此,虽然手册页将 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
值的 copy .形式参数的语义基本上是用实际函数参数初始化的局部变量的语义:
void *bar = baz;
MPI_Win_allocate_shared(..., &bar, ...);
这会将一个新值写入 bar
,同时保持 baz
的值不变。这就是为什么在 MPI_WRAP
中调用 MPI_Win_allocate_shared
后你会看到一个新值,但一旦它 return 到调用函数就会看到旧值。
后者类似于
void **bar = &baz;
MPI_Win_allocate_shared(..., bar, ...);
这具有完全不同的语义。 bar
现在包含 baz
的地址,这就是 MPI_Win_allocate_shared
将分配的缓冲区地址写入的位置。
所以正确的C/C++代码是:
void foo(void **bar) {
MPI_Win_allocate_shared(..., bar, ...);
}
void *baz;
foo(&baz);
C++有引用,同样可以这样写:
void foo(void *&bar) {
MPI_Win_allocate_shared(..., &bar, ...);
}
void *baz;
foo(baz);
这与第一个(不正确的)情况非常相似,关键区别在于这里的形式参数 bar
是实际参数 baz
的别名,所以现在 &bar
与 &baz
相同。因此,MPI_Win_allocate_shared
会将 return 值写入 baz
的存储区 space。
旁注:我推荐 Open MPI 的手册页,因为那里的解释基本上是 MPI 标准的摘录。